home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2005 March / Macworld CD March 2005 - Marathon Trilogy.iso / Shareware World / Text Processing / HexEdit Release.sit / HexEdit Release / Project / Source / EditWindow.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-10-31  |  92.1 KB  |  3,255 lines  |  [TEXT/CWIE]

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is Copyright 1993 Jim Bumgardner.
  13.  * 
  14.  * The Initial Developer of the Original Code is Jim Bumgardner
  15.  * Portions created by Lane Roathe (LR) are
  16.  * Copyright (C) Copyright © 1996-2002.
  17.  * All Rights Reserved.
  18.  *
  19.  * Modified: $Date: 2004/10/31 19:09:58 $
  20.  * Revision: $Id: EditWindow.c,v 1.71 2004/10/31 19:09:58 raving Exp $
  21.  *
  22.  * Contributor(s):
  23.  *        Lane Roathe
  24.  *        Nick Shanks (NS)
  25.  *        Scott E. Lasley (SEL) 
  26.  *        Brian Bergstrand (BB) 
  27.  *        Nick Pissaro Jr. (NP)
  28.  */
  29.  
  30. // 05/10/01 - GAB: MPW environment support
  31. #ifdef __MPW__
  32. #include "MPWIncludes.h"
  33. #endif
  34.  
  35. #include <stdio.h>
  36. #include <stdlib.h> // BB: bring in abs()
  37.  
  38. #include "EditWindow.h"
  39. #include "EditRoutines.h"
  40. #include "EditScrollbar.h"
  41. #include "HexSearch.h"
  42. #include "HexCompare.h"
  43. #include "Menus.h"
  44. #include "Prefs.h"
  45. #include "Utility.h"
  46.  
  47. // Create a new main theWin using a 'WIND' template from the resource fork
  48.  
  49. //LR 177 SInt16            CompareFlag = 0;
  50.  
  51. HEColorTableHandle ctHdl = NULL;    // LR: global to file, for speed
  52.  
  53. RGBColor black = { 0, 0, 0 };
  54. RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF };
  55.  
  56. RGBColor grey = { 0x7FFF, 0x7FFF, 0x7FFF };
  57.  
  58. // BB: selector to determine Nav dialog type
  59. #define kNavOpenDialogType ((NavCallBackUserData)-1L)
  60. enum
  61. {
  62.     kNavDITLID = 15000,
  63.     kNavDITLHeight = 40,//18,
  64.     kNavDITLWidth = 350,//234
  65.     kDataForkRadioID = 2,
  66.     kRsrcForkRadioID = 3,
  67.     kAutoForkRadioID = 4,
  68.     kNavDITLNumControls = 4//3 radio buttons + radio group control
  69. };
  70.  
  71. /*** NEW OFFSCREEN GWORLD ***/
  72. // LR: create offscreen drawing surface (so drawing to screen is not flickery)
  73. //LR 180 -- removed old comments, now always creates offscreen at current color depth
  74.  
  75. static GWorldPtr _newCOffScreen( short width, short height )
  76. {
  77.     OSStatus    error;
  78.     GWorldPtr    theGWorld;
  79.     Rect        rect;
  80.     
  81.     SetRect( &rect, 0, 0, width, height );
  82.     error = NewGWorld( &theGWorld, /*LR 177gPrefs.useColor? 0:1*/ 0, &rect, NULL, NULL, keepLocal );
  83.  
  84.     if( error != noErr ) return NULL;
  85.     return theGWorld;
  86. }
  87.  
  88. /*** ENSURE NAME IS UNIQUE ***/    
  89. // LR: complete re-write as this function used to create bogus names and overwrite memory
  90. // LR: 1.66 -- another rewrite, to create more "readable" names
  91. static void _ensureNameIsUnique( FSSpec *tSpec )
  92. {
  93.     OSStatus err;
  94.     FInfo fInfo;
  95.     int i = tSpec->name[0], num = 1;
  96.  
  97.     // Weird compiler bug, having the OS call in the while loop can caues it to fail w/o error
  98.     do
  99.     {
  100.         err = HGetFInfo( tSpec->vRefNum, tSpec->parID, tSpec->name, &fInfo );
  101.         if( err != fnfErr )
  102.         {
  103.             Str31 numstr;
  104.  
  105.             NumToString( num++, numstr );    // get string equiv
  106.  
  107.             if( i > 30 - numstr[0] )
  108.                 i = 30 - numstr[0];        // don't make too long of a name
  109.  
  110.             tSpec->name[i + 1] = ' ';
  111.             BlockMoveData( numstr + 1, &tSpec->name[i + 2], numstr[0] );
  112.  
  113.             tSpec->name[0] = i + 1 + numstr[0];
  114.         }
  115.     }while( err != fnfErr && i );
  116. }
  117.  
  118. /*** Set the window title (making sure it's good ***/    
  119. static void _setWindowTitle( EditWindowPtr dWin )
  120. {
  121.     MenuRef            windowMenu;
  122.     Str255 wintitle;
  123.     
  124.     // ABR: 1.9.1 use unmodified filename for window title
  125.     int l;
  126.     
  127.     l = (int)dWin->fsSpec.name[0];
  128.     BlockMoveData(dWin->fsSpec.name, wintitle, l+1);
  129.     
  130.     // LR: 1.7 Append fork in use to title
  131.     if( l < 255 - 9 )
  132.     {
  133.         Str31 str2;
  134.         
  135.         GetIndString( (StringPtr) str2, strHeader, dWin->fork );
  136.         
  137.         BlockMoveData( &str2[1], &wintitle[l+1], str2[0] );
  138.         
  139.         wintitle[0] = l + str2[0];
  140.     }
  141.     
  142.     SetWTitle( dWin->oWin.theWin, wintitle );
  143.     
  144.     // NS: 1.6.6 add window to window menu
  145.     // ABR: 1.9.1 use SetMenuItemText instead of MacAppendMenu to avoid parsing of meta-characters
  146.     windowMenu = GetMenuHandle( kWindowMenu );
  147.     
  148.     MacAppendMenu( windowMenu, "\px" );
  149.     SetMenuItemText( windowMenu, CountMenuItems(windowMenu), wintitle );
  150. }
  151.  
  152. /*** SETUP NEW EDIT WINDOW ***/
  153. //LR: 1.7 - static, and remove title (always fsSpec->name)
  154. //LR 177 -- Accept window type instead of checking global var
  155.  
  156. static OSStatus _setupNewEditWindow( EditWindowPtr dWin, tWindowType type )
  157. {
  158.     WindowRef theWin;
  159.     ObjectWindowPtr objectWindow;
  160.     short size;
  161.     Rect r;
  162.  
  163.     // NS 1.7.1; check for appearance and create appropriate window
  164.     theWin = InitObjectWindow( (g.useAppearance && g.systemVersion >= kMacOSEight) ? kAppearanceWindow : kSystem7Window, (ObjectWindowPtr) dWin, false );
  165.     if( !theWin )
  166.         ErrorAlert( ES_Fatal, errMemory );
  167.  
  168.     // LR: 1.7 set window title & get text for window menu
  169.     _setWindowTitle( dWin );
  170.  
  171.     objectWindow = (ObjectWindowPtr)dWin;
  172.     
  173.     objectWindow->Draw            = MyDraw;
  174.     objectWindow->Idle            = MyIdle;
  175.     objectWindow->HandleClick    = MyHandleClick;
  176.     objectWindow->Dispose        = DisposeEditWindow;
  177.     objectWindow->ProcessKey    = MyProcessKey;
  178.     objectWindow->Save            = SaveContents;
  179.     objectWindow->SaveAs        = SaveAsContents;
  180.     objectWindow->Revert        = RevertContents;
  181.     objectWindow->Activate        = MyActivate;
  182.  
  183. //LR 180    if( gPrefs.useColor )
  184.     dWin->csResID = gPrefs.csResID;    // LR: 1.5 - color selection
  185.     dWin->csMenuID = gPrefs.csMenuID;
  186. //LR 180    else
  187. //LR 180        dWin->csResID = -1;    // LR: if created w/o color then offscreen is 1 bit, NO COLOR possible!
  188.  
  189.     // Make it the current grafport
  190.     SetPortWindowPort( theWin );
  191.     
  192. //LR 180    dWin->offscreen = _newCOffScreen( kHexWindowWidth - kSBarSize, g.maxHeight - kHeaderHeight );    // LR: 1.7 - areas for scroll bar & header not needed!
  193. //LR 180    if( !dWin->offscreen )
  194. //LR 180            ErrorAlert( ES_Fatal, errMemory );
  195.  
  196.     SizeEditWindow( theWin, type );
  197.  
  198.     GetWindowPortBounds( theWin, &r );
  199.  
  200. //LR: 1.7 -fix lpp calculation!    dWin->linesPerPage = ( r.bottom - TopMargin - BotMargin - ( kHeaderHeight-1 ) ) / kLineHeight + 1;
  201.  
  202. /*LR 175 -- done in SetupScrollBars (this was causing bogus scrollbar values!)
  203.     dWin->linesPerPage = (maxheight - kHeaderHeight) / kLineHeight;
  204.     dWin->startSel = dWin->endSel = 0L;
  205.     dWin->editMode = EM_Hex;
  206.     dWin->lastTypePos = -1;    //LR 1.72 -- allow insertion before first char to get into undo buffer
  207. */
  208.     //LR: 1.7 - what was this??? ((WStateData *) *((WindowPeek)theWin)->dataHandle)->stdState.left + kHexWindowWidth;
  209.  
  210.     LocalToGlobal( (Point *)&r.top );
  211.     LocalToGlobal( (Point *)&r.bottom );
  212.  
  213.     //LR 190 -- Zoom state is now smaller for large files (big window) and larger for small files (small window)
  214.     if( r.bottom - r.top < g.maxHeight / 2 )
  215.         size = g.maxHeight - r.top;
  216.     else
  217.         size = (r.bottom - r.top) / 2;
  218.  
  219.     r.bottom = (r.top + ((size - kHeaderHeight) / kLineHeight) * kLineHeight) + kHeaderHeight;
  220.  
  221.     SetWindowStandardState( theWin, &r );
  222.  
  223.     return noErr;
  224. }
  225.  
  226. #pragma mark -
  227.  
  228. #define DataItem        11
  229. #define RsrcItem        12
  230. #define SmartItem        13
  231.  
  232. #if !defined(__MC68K__) && !defined(__SC__)        //LR 1.73 -- not available for 68K (won't even link!)
  233. /*** NAV SERVICES EVENT FILTER ***/
  234. static pascal void _navEventFilter( NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, NavCallBackUserData callBackUD )
  235. {
  236.     static Handle navDITL = NULL; // BB: custom control DITL
  237.     
  238.     // BB: setup and handle custom NavGet controls - Fixes bug #229519
  239.     if( callBackUD == kNavOpenDialogType )
  240.     {
  241.         //short theItem;
  242.         short itemCount;
  243.         ControlRef theControl;
  244.         DialogPtr theDialog;
  245.         switch( callBackSelector )
  246.         {
  247.             case kNavCBCustomize://Negotiate the custom area size
  248.                  if( callBackParms->customRect.bottom == 0 )
  249.                  {
  250.                     callBackParms->customRect.bottom = callBackParms->customRect.top+kNavDITLHeight;
  251.                     callBackParms->customRect.right = callBackParms->customRect.left+kNavDITLWidth;
  252.                 }
  253.                 break;
  254.             
  255.             case kNavCBStart:
  256.                 navDITL = GetResource( 'DITL', kNavDITLID );    //LR 1.73 -- no need to keep loaded, resource manager does that for us!
  257.                 if( navDITL != NULL )
  258.                 {
  259.                     theDialog = GetDialogFromWindow( callBackParms->window );
  260.                     itemCount = CountDITL( theDialog );
  261.                     if( NavCustomControl( callBackParms->context, kNavCtlAddControlList, navDITL ) == noErr)
  262.                     {
  263.                         //since Nav Services won't work w/o the AppearanceMgr, we go ahead and use Appearance calls w/o checking
  264.                         short i = itemCount+kDataForkRadioID;
  265.                         //init the controls
  266.                         for( ; i <= (itemCount+kRsrcForkRadioID); ++i )
  267.                         {
  268.                             GetDialogItemAsControl( theDialog, i, &theControl );
  269.                             if( theControl != NULL )
  270.                                 SetControlValue( theControl, 0 );
  271.                         }
  272.                         GetDialogItemAsControl( theDialog, itemCount+kAutoForkRadioID, &theControl );
  273.                         if( theControl != NULL )
  274.                             SetControlValue( theControl, 1 );
  275.                     }
  276.                 }    
  277.                 break;
  278.             
  279.             case kNavCBTerminate:
  280.                 if( navDITL != NULL )
  281.                 {
  282.                     short i;
  283.                     theDialog = GetDialogFromWindow( callBackParms->window );
  284.                     itemCount = CountDITL( theDialog );
  285.                     //set the fork mode based on the selection
  286.                     for( i = itemCount; i >= itemCount - 2; --i )
  287.                     {
  288.                         GetDialogItemAsControl( theDialog, i, &theControl );
  289.                         if( theControl != NULL )
  290.                         {
  291.                             if( GetControlValue( theControl) >= 1 )
  292.                             {
  293.                                 g.forkMode = abs( (i - itemCount) ) + 1; //dependant on ForkModes being 1,2,3
  294.                                 //the FM_Data and FM_Smart modes will be reversed
  295.                                 if( g.forkMode == FM_Smart ) g.forkMode = FM_Data;
  296.                                 else if( g.forkMode == FM_Data ) g.forkMode = FM_Smart;
  297.                                 break;
  298.                             }
  299.                         }
  300.                     }
  301.                     ReleaseResource( navDITL );
  302.                     navDITL = NULL;
  303.                 }
  304.                 break;
  305.         }
  306.     }
  307. }
  308.  
  309. /*** NAV SERVICES PREVIEW FILTER ***/
  310. /*
  311. static pascal Boolean _navPreviewFilter( NavCBRecPtr callBackParms, void *callBackUD )
  312. {
  313.     #pragma unused( callBackParms, callBackUD )
  314.     return false;
  315. }
  316. */
  317.  
  318. /*** NAV SERVICES FILE FILTER ***/
  319. /*
  320. static pascal Boolean _navFileFilter( AEDesc* theItem, void* info, void *callBackUD, NavFilterModes filterMode )
  321. {
  322.     #pragma unused( theItem, info, callBackUD, filterMode )
  323.     return true;
  324. }
  325. */
  326. #endif    //POWERPC
  327.  
  328. #if !TARGET_API_MAC_CARBON        // standard file callbacks not applicable with carbon
  329.  
  330. /*** SOURCE DLOG HOOK ***/
  331. //LR 1.72 -- at some point the fork mode was changed from zero to one based,
  332. //            probably in my contants cleanup. This caused the WRONG control to be
  333. //            selected for non-appearance cases ... and then CRASH!
  334. static pascal short _sourceDLOGHook( short item, DialogPtr theDialog )
  335. {
  336.     switch( item )
  337.     {
  338.         case DataItem:
  339.         case RsrcItem:
  340.         case SmartItem:
  341.             SetControl( theDialog, g.forkMode + (DataItem - 1), false );
  342.             g.forkMode = item - (DataItem - 1);
  343. //LR 185            SetControl( theDialog, g.forkMode + (DataItem - 1), true );
  344. //LR 185            return sfHookNullEvent;    /* Redraw the List */
  345.         
  346.         case sfHookFirstCall:
  347.             SetControl( theDialog, g.forkMode + (DataItem - 1), true );
  348.             return sfHookNullEvent;
  349.     }
  350.     return item;
  351. }
  352.  
  353. /*** SOURCE DLOG FILTER ***/
  354. /*LR 180 -- removed, now set prompt string at launch
  355. static pascal Boolean _sourceDLOGFilter( DialogPtr dlg, EventRecord *event, short *item )
  356. {
  357.     Str63        prompt;
  358.  
  359.     if( activateEvt == event->what )
  360.     {
  361.         GetIndString( prompt, strPrompt, CompareFlag+2 );    // LR: v1.6.5 localizable way!
  362.         SetText( dlg, 14, prompt );
  363.     }
  364.  
  365.     return StdFilterProc( dlg, event, item );
  366. }
  367. */
  368.  
  369. #endif
  370.  
  371. /*** ASK EDIT WINDOW ***/
  372. #if !defined(__MC68K__) && !defined(__SC__)        //LR 1.73 -- not available for 68K (won't even link!)
  373. short AskEditWindowNav( tWindowType type )
  374. {
  375. //#if TARGET_API_MAC_CARBON    // LR: v1.6  -- BB no longer used
  376.     OSStatus error = noErr;
  377.     NavReplyRecord        reply;
  378.     NavDialogOptions    dialogOptions;
  379.      NavEventUPP            eventProc = NewNavEventUPP( _navEventFilter );
  380.     NavPreviewUPP        previewProc = NULL;
  381.     NavObjectFilterUPP    filterProc = NULL;
  382.     NavTypeListHandle    openTypeList = NULL;
  383.  
  384. #if TARGET_API_MAC_CARBON    //LR 175 -- just to require v1.1 (we crash under v1.0x!)
  385.     NavDialogCreationOptions opt;
  386.     NavGetDefaultDialogCreationOptions( &opt );
  387. #endif
  388.     
  389.     NavGetDefaultDialogOptions( &dialogOptions );
  390.     dialogOptions.dialogOptionFlags |= kNavNoTypePopup+kNavAllowInvisibleFiles; // BB: allow invisible files - fixes bug #425256
  391.     dialogOptions.dialogOptionFlags |= kNavSupportPackages+kNavAllowOpenPackages;   // benh57: allow browsing into packages. (496196)
  392.     GetIndString( dialogOptions.message, strPrompt, type + 2 );    //LR 180 -- modify prompt
  393.  
  394.     error = NavGetFile( NULL, &reply, &dialogOptions, eventProc, previewProc, filterProc, openTypeList, kNavOpenDialogType);
  395.     if( reply.validRecord || !error )
  396.     {
  397.         AEKeyword     keyword;
  398.         DescType     descType;
  399.         FSSpec        openedSpec;    
  400.         Size         actualSize;
  401.         
  402.         error = AEGetNthPtr( &(reply.selection), 1, typeFSS, &keyword, &descType, &openedSpec, sizeof(FSSpec), &actualSize );
  403.         if( !error )
  404.             OpenEditWindow( &openedSpec, type, true );
  405.  
  406.         NavDisposeReply( &reply );
  407.     }
  408.     else error = ioErr;        // user cancelled
  409.     DisposeNavEventUPP( eventProc );
  410.     AdjustMenus();
  411.     return error == noErr? 0 : -1;
  412. }
  413. #endif    //POWERPC
  414.  
  415. #if !TARGET_API_MAC_CARBON    // BB:  replaced
  416. short AskEditWindowSF( tWindowType type )
  417. {
  418.     SFReply        macSFReply;
  419.     FSSpec        fSpec;
  420.     long        procID;
  421.     Point        where = { -1, -1 };
  422.     Str255        prompt;
  423.  
  424.     DlgHookUPP myGetFileUPP;        // LR: v1.6.5 limited to this routine
  425. //LR 180    ModalFilterUPP myFilterUPP;
  426.  
  427.     myGetFileUPP = NewDlgHookProc( _sourceDLOGHook );
  428. //LR 180    myFilterUPP = NewModalFilterProc( _sourceDLOGFilter );
  429.  
  430.     // LR: make less of a hack!
  431. // LR: v1.6.5 localization    = { "\pFile to Open:", "\pFirst File to Compare:", "\pSecond File to Compare:"};
  432. /*
  433.     // LR: hacks for requesting different files for comparing…
  434.  
  435.     if( CompareFlag == 1 )
  436.         SFPGetFile( where, "\pFirst File to Compare:", NULL, -1, NULL, myGetFileUPP, &macSFReply, dlgGetFile, NULL );
  437.     else if( CompareFlag == 2 )
  438.         SFPGetFile( where, "\pSecond File to Compare:", NULL, -1, NULL, myGetFileUPP, &macSFReply, dlgGetFile, NULL );
  439.     else
  440. */
  441.     GetIndString( prompt, strPrompt, type + 2 );    //LR 177 -- send now, instead of modifying dialog later
  442.  
  443.     SFPGetFile( where, prompt, NULL, -1, NULL, myGetFileUPP, &macSFReply, dlgGetFile, /*LR 180 myFilterUPP*/ NULL );
  444.  
  445.     DisposeDlgHookUPP( myGetFileUPP );
  446. //LR 180    DisposeModalFilterUPP( myFilterUPP );
  447.  
  448.     if( macSFReply.good )
  449.     {
  450.         BlockMove( macSFReply.fName, fSpec.name, macSFReply.fName[0]+1 );
  451.         GetWDInfo( macSFReply.vRefNum, &fSpec.vRefNum, &fSpec.parID, &procID );
  452.         OpenEditWindow( &fSpec, type, true );
  453.     }
  454.     else return -1;
  455.  
  456.     AdjustMenus();
  457.     return 0;
  458. }
  459. #endif
  460.  
  461. #pragma mark -
  462.  
  463. /*** CLEANUP EDITOR ***/
  464. void CleanupEditor( void )
  465. {
  466.     PrefsSave();
  467.  
  468.     // LR: v1.6.5 now need to dispose of these at exit since they never truly "close"
  469.     if( g.searchDlg )
  470.     {
  471.         DisposeDialog( g.searchDlg );
  472.         g.searchDlg = NULL;
  473.     }
  474.  
  475.     if( g.gotoDlg )
  476.     {
  477.         DisposeDialog( g.gotoDlg );
  478.         g.gotoDlg = NULL;
  479.     }
  480. }
  481.  
  482. /*** INITIALIZE EDITOR ***/
  483. void InitializeEditor( void )
  484. {
  485. //LR 175    CursHandle    cursorHandle = NULL;
  486.     Str255        str;
  487.     SInt32        val;
  488.     FontInfo    finfo;
  489.     WindowRef    newWin;
  490. #if !TARGET_API_MAC_CARBON    // LR: v1.6
  491.     PScrapStuff            ScrapInfo;
  492.  
  493.     ScrapInfo = InfoScrap();
  494.     if( ScrapInfo->scrapState < 0 )
  495.         ZeroScrap();
  496. #endif
  497.  
  498.     // Start Profiling
  499. #if PROFILE            // 6/15 Optional profiling support
  500.     freopen( "profile.log", "w", stdout );        // If console isn't wanted
  501.     InitProfile( 200, 200 );
  502.     _profile = 0;
  503.     // cecho2file( "profile.log", false, stdout );    // If console is wanted
  504. #endif
  505.  
  506. #if TARGET_API_MAC_CARBON    // LR: v1.6
  507. {
  508. /*LR 180 -- system call takes into account doc!
  509.     BitMap qdScreenBits;
  510.  
  511.     GetQDGlobalsScreenBits( &qdScreenBits );
  512.     g.maxHeight = qdScreenBits.bounds.bottom - qdScreenBits.bounds.top - 24;
  513. */
  514.     Rect r;
  515.  
  516.     GetAvailableWindowPositioningBounds( GetMainDevice(), &r );
  517.     g.maxHeight = r.bottom - r.top - GetMBarHeight();    //LR 191 -- remove menu bar height
  518. }
  519. #else
  520.     g.maxHeight = qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - GetMBarHeight();    // LR: add 'qd.'
  521. #endif
  522.  
  523.     //LR 1.72 -- more flexability in font usage, get from string and find width/height from actual data
  524.  
  525.     newWin = GetNewCWindow( (g.useAppearance && g.systemVersion >= kMacOSEight) ? kAppearanceWindow : kSystem7Window, NULL, kLastWindowOfClass );    //LR 1.72 don't change system font!
  526.     SelectWindow( newWin );
  527.     SetPortWindowPort( newWin );
  528.  
  529.     GetIndString( str, strFont, 1 );
  530.     GetFNum( str, &g.fontFaceID );        // 1.7 carsten-unhardcoded font name & size
  531.     GetIndString( str, strFont, 2 );
  532.     StringToNum( str, &val );            //LR 1.72 -- get font info from resource
  533.     g.fontSize = (short)val;
  534.     TextFont( g.fontFaceID );
  535.     TextSize( g.fontSize );
  536.     GetFontInfo( &finfo );
  537.     g.charWidth = CharWidth( '0' );    //LR -- should, but doesn't, work -> finfo.widMax;
  538.     g.lineHeight = finfo.ascent + finfo.descent;
  539.  
  540.     DisposeWindow( newWin );    // done w/temp window, get rid of it
  541.  
  542.     //LR 177 -- create global offscreen drawing surface
  543.  
  544.     g.offscreen = _newCOffScreen( kHexWindowWidth - kSBarSize, g.maxHeight - kHeaderHeight );    // LR: 1.7 - areas for scroll bar & header not needed!
  545.     if( !g.offscreen )
  546.             ErrorAlert( ES_Fatal, errMemory );
  547.  
  548.     //LR 160 -- start up printing in classic mode
  549.  
  550. #if !TARGET_API_MAC_CARBON
  551.     PrOpen();
  552.     g.HPrint = (THPrint) NewHandle( sizeof(TPrint) );
  553.     if( !g.HPrint )
  554.         ErrorAlert( ES_Fatal, errMemory );
  555.  
  556.     PrintDefault( g.HPrint );
  557.     PrClose();
  558. #endif
  559. }
  560.  
  561. /*** SIZE A WINDOW APPR. TO SITUATION ***/
  562. //LR 175 -- seperated to allow calling from OpenWindow to handle compare requests on open windows
  563. //NP 177 -- Global for compare's usage
  564. //LR 177 -- added window type parameter from NP's suggestion :)
  565.  
  566. void SizeEditWindow( WindowRef theWin, tWindowType type )
  567. {
  568.     EditWindowPtr dWin = (EditWindowPtr)GetWRefCon( theWin );
  569.     short maxheight;
  570.     Rect r;
  571.  
  572.     // LR:    Hack for comparing two files
  573.     if( kWindowCompareTop == type )
  574.     {
  575.         maxheight = g.maxHeight / 2 - 96;
  576.         MoveWindow( theWin, 14, 48, true );
  577.         CompWind1 = theWin;
  578.     }
  579.     else if( kWindowCompareBtm == type )
  580.     {
  581.         maxheight = g.maxHeight / 2 - 96;        //LR 180 -- required to keep window of correct height
  582.         MoveWindow( theWin, 14, maxheight + 48, true );
  583.         CompWind2 = theWin;
  584.     }
  585.     else    // kWindowNormal
  586.     {
  587.         maxheight = g.maxHeight;
  588.  
  589.         //LR 180 -- make sure bottom of window doesn't go off end of screen
  590.         //    NOTE:    Carbon top is positive, classic is negative!
  591.         GetWindowBounds( theWin, kWindowStructureRgn, &r );
  592.         if( r.top < GetMBarHeight() )
  593.         {
  594.             r.top = (short)(GetMBarHeight() * 2);            //LR 191 -- don't allow window to be under menu bar
  595.             MoveWindow( theWin, r.left, r.top, true );
  596.         }
  597.         maxheight -= r.top;
  598.     }
  599.  
  600.     // Check for best window size
  601.     if( (dWin->fileSize / kBytesPerLine) * kLineHeight < maxheight )
  602.     {
  603.         maxheight = (((dWin->fileSize + (kBytesPerLine - 1)) / kBytesPerLine) * kLineHeight);
  604.  
  605.         // Make sure window is at least of some usable size!
  606.         if( maxheight < (kLineHeight * 10) )
  607.             maxheight = (kLineHeight * 10);
  608.     }
  609.  
  610.     // LR: v1.6.5 round this to a size showing only full lines
  611.     maxheight = ((maxheight / kLineHeight) * kLineHeight) + kHeaderHeight;
  612.  
  613.     SizeWindow( theWin, kHexWindowWidth, maxheight, true );
  614.  
  615.     // Show the theWin
  616.     SelectWindow( theWin );
  617.     ShowWindow( theWin );
  618.  
  619.     SetupScrollBars( dWin );
  620. }
  621.  
  622. /*** CLOSE EDIT WINDOW ***/
  623. Boolean    CloseEditWindow( WindowRef theWin )
  624. {
  625.     short            i, n;
  626. //    Str63            fileName;
  627.     Str255            windowName, menuItemTitle;
  628.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  629.     MenuRef            windowMenu;
  630.  
  631.     MySetCursor( C_Arrow );
  632.  
  633.     if( dWin->dirtyFlag )
  634.     {
  635. //LR 1.72        GetWTitle( theWin, fileName );
  636.         if( !g.useNavServices ) // BB: use Nav Services ?
  637.         {
  638.             ParamText( dWin->fsSpec.name, NULL, NULL, NULL );
  639.             switch( CautionAlert( alertSave, NULL ) )
  640.             {
  641.                 case ok:
  642.                     SaveContents( theWin );    
  643.                     break;
  644.                     
  645.                 case cancel:
  646.                     return false;
  647.                     
  648.                 case 3:
  649.                     // Discard
  650.                     break;
  651.             }
  652.         }
  653. #if !defined(__MC68K__) && !defined(__SC__)        //LR 1.73 -- not available for 68K (won't even link!)
  654.         else        // BB: code to support Nav Services
  655.         {
  656.             OSStatus error = noErr;
  657.             NavAskSaveChangesResult        reply;
  658.             NavDialogOptions    dialogOptions;
  659.             NavEventUPP            eventProc = NewNavEventUPP( _navEventFilter );
  660.  
  661.             NavGetDefaultDialogOptions( &dialogOptions );
  662.             BlockMoveData( dWin->fsSpec.name, dialogOptions.savedFileName, dWin->fsSpec.name[0]+1 );//set the file name string
  663.             error = NavAskSaveChanges( &dialogOptions, kNavSaveChangesClosingDocument, &reply, eventProc, NULL );
  664.             if( error != noErr )    return false; //on error, make sure we don't destroy the contents
  665.             switch( reply )
  666.             {
  667.                 case kNavAskSaveChangesSave:
  668.                     SaveContents( theWin );
  669.                     break;
  670.                 
  671.                 case kNavAskSaveChangesCancel:
  672.                     return false;
  673.                     
  674.                 case kNavAskSaveChangesDontSave:
  675.                     break;                
  676.             }
  677.             
  678.             DisposeNavEventUPP( eventProc );
  679.         }
  680. #endif    //POWERPC
  681.     }
  682.  
  683.     // NS: v1.6.6, remove window from menu on closing
  684.     GetWTitle( theWin, windowName );
  685.     windowMenu = GetMenuHandle( kWindowMenu );
  686.     n = CountMenuItems(windowMenu);
  687.     for( i = 1; i <= n; i++ )
  688.     {
  689.         GetMenuItemText( windowMenu, i, menuItemTitle );
  690.         if( EqualPStrings( windowName, menuItemTitle ) )
  691.         {
  692.             DeleteMenuItem( windowMenu, i );
  693.             n = i+1;
  694.         }
  695.     }
  696.  
  697.     //LR 1.73 :if a compare window, clear ptr so compare routine can exit!
  698.     if( theWin == CompWind1 )
  699.         CompWind1 = NULL;
  700.     if( theWin == CompWind2 )
  701.         CompWind2 = NULL;
  702.  
  703.     ((ObjectWindowPtr)dWin)->Dispose( theWin );
  704.  
  705.     // LR: v1.7 -- if no edit window available, close find windows
  706.     if( !FindFirstEditWindow() )
  707.     {
  708.         if( g.gotoDlg )
  709.             HideWindow( GetDialogWindow( g.gotoDlg ) );
  710.         if( g.searchDlg )
  711.             HideWindow( GetDialogWindow( g.searchDlg ) );
  712.     }
  713.  
  714.     return true;
  715. }
  716.  
  717. /*** CLOSE ALL EDIT WINDOWS ***/
  718. Boolean CloseAllEditWindows( void )
  719. {
  720.     WindowRef next, theWin = FrontNonFloatingWindow();
  721.  
  722.     while( theWin )
  723.     {
  724.         long windowKind = GetWindowKind( theWin );
  725.  
  726.         next = GetNextWindow( theWin );
  727.  
  728. /*LR 1.7 -- now closed if no windows open!
  729.         if( (DialogPtr)theWin == g.searchDlg )
  730.         {
  731.             DisposeDialog( g.searchDlg );
  732.             g.searchDlg = NULL;
  733.         }
  734.         else*/
  735.         if( windowKind == kHexEditWindowTag )
  736.             if( !CloseEditWindow( theWin ) )
  737.                 return false;
  738.  
  739.         theWin = next;
  740.     }
  741.  
  742.     return true;
  743. }
  744.  
  745. /*** OPEN EDIT WINDOW ***/
  746. // LR 177 -- Now accepts window kind as a parameter instead of using global var CompareFlag
  747.  
  748. OSStatus OpenEditWindow( FSSpec *fsSpec, tWindowType type, Boolean showerr )
  749. {
  750. // LR: 1.5    WindowRef    theWin;
  751.     EditWindowPtr        dWin;
  752.     OSStatus            error;
  753.     short                refNum=0;    //LR 181 -- , redo = false;
  754. //LR 175    Point                where={-1, -1};
  755.     HParamBlockRec        pb;
  756.     FSSpec                workSpec;
  757.     Str31                tempStr;
  758.     long                fileEOF;    //LR 175
  759. // LR: 1.5     Rect        r, offRect;
  760.  
  761.     //LR 175 -- try to find the file in an open window first, and use it if found
  762.     if( NULL != (dWin = LocateEditWindow( fsSpec, g.forkMode == FM_Smart ? -1 : g.forkMode )) )
  763.     {
  764. //LR 180        SizeEditWindow( dWin->oWin.theWin, type );
  765.         SelectWindow( dWin->oWin.theWin );
  766.         return( noErr );
  767.     }
  768.  
  769.     // Get the Template & Create the Window, it is set up in the resource fork
  770.     // to not be initially visible 
  771.  
  772.     pb.fileParam.ioCompletion = 0l;
  773.     pb.fileParam.ioNamePtr = fsSpec->name;
  774.     pb.fileParam.ioVRefNum = fsSpec->vRefNum;
  775.     pb.fileParam.ioDirID = fsSpec->parID;
  776.     pb.fileParam.ioFDirIndex = 0;
  777.  
  778.     if( ( error = PBHGetFInfoSync( &pb ) ) != noErr )
  779.     {
  780.         if( showerr )
  781.             ErrorAlert( ES_Caution, errFileInfo, error );
  782.  
  783.         return( error );
  784.     }
  785.  
  786.     // Allocate our edit window storage
  787.     dWin = (EditWindowPtr) NewPtrClear( sizeof(EditWindowRecord) );
  788.     if( !dWin )
  789.     {
  790.         error = MemError();
  791.         if( showerr )
  792.             ErrorAlert( ES_Caution, errMemory );
  793.  
  794.         return( error );
  795.     }
  796.  
  797.     // Handle the Opening of the Data Fork
  798.  
  799.     if( g.forkMode == FM_Data || (pb.fileParam.ioFlLgLen > 0 && g.forkMode == FM_Smart) )
  800.     {
  801.         dWin->fork = FT_Data;
  802. //LR 175        error = HOpenDF( fsSpec->vRefNum, fsSpec->parID, fsSpec->name, fsRdPerm, &refNum );
  803.         error = FSpOpenDF( fsSpec, fsRdWrPerm, &refNum );
  804.         if( error )
  805.         {
  806.             dWin->readOnlyFlag = true;
  807.             error = FSpOpenDF( fsSpec, fsRdPerm, &refNum );    //LR 180 -- on error try to open read-only
  808.         }
  809.         // Check for empty for this way instead of via pb.fileParam.ioFlLgLen so that the user can create the fork if desired!
  810.         if( !error )
  811.             error = GetEOF( refNum, &fileEOF );        //LR 175
  812.  
  813.         if( error == fnfErr || (!error && 0 == fileEOF) )
  814.         {
  815.             if( showerr )
  816.             {
  817.                 GetIndString( tempStr, strFiles, FN_DATA );
  818.                 ParamText( fsSpec->name, tempStr, NULL, NULL );
  819.  
  820.                 if( StopAlert( alertNoFork, NULL ) == 2 )
  821.                     goto contData;
  822.             }
  823.  
  824.             error = fnfErr;        //LR 180 -- save lots of dup'd code (and prevent future missed mods)
  825.             goto exitErr;
  826.  
  827. /*LR 175 -- empty forks are always opened, so we just have to warn about them being empty!
  828.  
  829. //LR 175            error = HCreate( fsSpec->vRefNum, fsSpec->parID, fsSpec->name, 
  830.             error = FSpCreate( fsSpec, pb.fileParam.ioFlFndrInfo.fdCreator, pb.fileParam.ioFlFndrInfo.fdType, smSystemScript );
  831.             if( error != noErr )
  832.             {
  833.                 ErrorAlert( ES_Caution, errCreate, error );
  834.                 return error;
  835.             }
  836. //LR 175            error = HOpenDF( fsSpec->vRefNum, fsSpec->parID, fsSpec->name, fsRdPerm, &refNum );
  837.             error = FSpOpenDF( fsSpec, fsRdWrPerm, &refNum );
  838. */
  839.         }
  840.         else if( error != noErr )
  841.         {
  842. contErr:
  843.             if( showerr )
  844.                 ErrorAlert( ES_Caution, errOpen, error );
  845. exitErr:
  846.             if( dWin )
  847.                 DisposePtr( (Ptr)dWin );        //LR 180 -- no memory leaks!
  848.  
  849.             if( refNum )
  850.                 FSClose( refNum );        //LR 175
  851.  
  852.             return( error );
  853.         }
  854. contData:
  855.         dWin->fileSize = pb.fileParam.ioFlLgLen;
  856.     }
  857.     else        // otherwise, Open the Resource Fork
  858.     {
  859.         dWin->fork = FT_Resource;
  860. //LR 175        error = HOpenRF( fsSpec->vRefNum, fsSpec->parID, fsSpec->name, fsRdPerm, &refNum );
  861.         error = FSpOpenRF( fsSpec, fsRdWrPerm, &refNum );
  862.         if( error )
  863.         {
  864.             dWin->readOnlyFlag = true;
  865.             error = FSpOpenRF( fsSpec, fsRdPerm, &refNum );    //LR 180 -- on error try to open read-only
  866.         }
  867.         // Check for empty for this way instead of via pb.fileParam.ioFlRLgLen so that the user can create the fork if desired!
  868.         if( !error )
  869.             error = GetEOF( refNum, &fileEOF );        //LR 175
  870.  
  871.         if( error == fnfErr || (!error && 0 == fileEOF) )
  872.         {
  873.             if( showerr )
  874.             {
  875.                 GetIndString( tempStr, strFiles, FN_RSRC );
  876.                 ParamText( fsSpec->name, tempStr, NULL, NULL );
  877.                 if( StopAlert( alertNoFork, NULL ) == 2 )
  878.                     goto contRsrc;
  879.             }
  880.  
  881.             error = fnfErr;        //LR 180 -- save lots of dup'd code (and prevent future missed mods)
  882.             goto exitErr;
  883.  
  884. /*LR 175 -- empty forks are always opened, so we just have to warn about them being empty!
  885.  
  886. //LR 175            HCreateResFile( fsSpec->vRefNum, fsSpec->parID, fsSpec->name );
  887.             FSpCreateResFile( fsSpec, pb.fileParam.ioFlFndrInfo.fdCreator, pb.fileParam.ioFlFndrInfo.fdType, smSystemScript );
  888.             if( ( error = ResError() ) != noErr )
  889.             {
  890.                 ErrorAlert( ES_Caution, errCreate, error );
  891.                 return error;
  892.             }
  893. //LR 175            error = HOpenRF( fsSpec->vRefNum, fsSpec->parID, fsSpec->name, fsRdPerm, &refNum );
  894.             error = FSpOpenRF( fsSpec, fsRdWrPerm, &refNum );
  895. */
  896.         }
  897.         else if( error != noErr )
  898.             goto contErr;
  899. contRsrc:
  900.         dWin->fileSize = pb.fileParam.ioFlRLgLen;
  901.     }
  902.  
  903.     /* if we get here, we have a valid file and data to read, or an empty file to work with */
  904.     /* now, for OS X, we need to get the catalog information for later restoration when saving (file permissions) */
  905.  
  906. #if !defined(__MC68K__) && !defined(__SC__)
  907.     if( FSGetCatalogInfo )    /* not available in all systems (OS 9 and later only it seems) */
  908.     {
  909.         FSRef ref;
  910.  
  911.         error = FSpMakeFSRef( fsSpec, &ref );
  912.         if( !error )
  913.         {
  914.             error = FSGetCatalogInfo( &ref, kFSCatInfoGettableInfo, &dWin->catinfo, NULL/*name*/, NULL/*FSSpec*/, NULL/*parent*/ );
  915.             dWin->OKToSetCatInfo = !error;
  916.         }
  917.     }
  918. #endif
  919.  
  920.     /* Get a working file, in the temporary folder */
  921.     dWin->refNum = refNum;
  922.     workSpec = *fsSpec;
  923.     error = FindFolder( kOnSystemDisk, kTemporaryFolderType, kCreateFolder, &workSpec.vRefNum, &workSpec.parID );
  924.     if( error != noErr )
  925.     {
  926.         if( showerr )
  927.             ErrorAlert( ES_Caution, errFindFolder, error );
  928.         return error;
  929.     }
  930.  
  931.     if( workSpec.name[0] < 31 )
  932.     {
  933.         workSpec.name[0]++;
  934.         workSpec.name[workSpec.name[0]] = '^';    //LR 1.72 -- temp filenames end with ^
  935.     }
  936.     else
  937.         workSpec.name[31] ^= 0x10;
  938.  
  939.     _ensureNameIsUnique( &workSpec );
  940. //LR 175    error = HCreate( workSpec.vRefNum, workSpec.parID, workSpec.name, kAppCreator, '????' );
  941.     error = FSpCreate( &workSpec, kAppCreator, '????', smSystemScript );
  942.     if( error != noErr )
  943.     {
  944.         if( showerr )
  945.             ErrorAlert( ES_Caution, errCreate, error );
  946.         return error;
  947.     }
  948. //LR 181    redo = false;
  949.  
  950. //LR 175    error = HOpen( workSpec.vRefNum, workSpec.parID, workSpec.name, fsRdWrPerm, &refNum );
  951.     error = FSpOpenDF( &workSpec, fsRdWrPerm, &refNum );
  952.     if( error != noErr )
  953.     {
  954.         if( showerr )
  955.             ErrorAlert( ES_Caution, errOpen, error );
  956.         return error;
  957.     }
  958.  
  959.     /* setup our window varaiables */
  960.     dWin->workSpec = workSpec;
  961.     dWin->workRefNum = refNum;
  962.     dWin->workBytesWritten = 0L;
  963.  
  964.     dWin->fileType = pb.fileParam.ioFlFndrInfo.fdType;
  965.     dWin->creator = pb.fileParam.ioFlFndrInfo.fdCreator;
  966.     dWin->creationDate = pb.fileParam.ioFlCrDat;
  967.  
  968.     dWin->fsSpec =
  969.     dWin->destSpec = *fsSpec;
  970.  
  971.     error = _setupNewEditWindow( dWin, type );    // LR: 1.5 -make maintenence easier!
  972.     if( !error )
  973.         LoadFile( dWin );
  974.  
  975.     return error;
  976. }
  977.  
  978. /*** DISPOSE EDIT WINDOW ***/
  979. void DisposeEditWindow( WindowRef theWin )
  980. {
  981.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  982.  
  983.     UnloadFile( dWin );
  984.     if( dWin->refNum ) FSClose( dWin->refNum );
  985.     if( dWin->workRefNum )
  986.     {
  987.         FSClose( dWin->workRefNum );
  988.         FSpDelete( &dWin->workSpec );
  989. //LR 175        HDelete( dWin->workSpec.vRefNum, dWin->workSpec.parID, dWin->workSpec.name );
  990.     }
  991.  
  992.     //LR 1.72 -- release undo if associated with this window
  993.     if( dWin == gUndo.theWin )
  994.     {
  995.         ReleaseEditScrap( dWin, &gUndo.undoScrap );
  996.         gUndo.type = 0;
  997.     }
  998.     if( dWin == gRedo.theWin )
  999.     {
  1000.         ReleaseEditScrap( dWin, &gRedo.undoScrap );
  1001.         gRedo.type = 0;
  1002.     }
  1003.  
  1004. //LR 180    DisposeGWorld( dWin->offscreen );
  1005.     DefaultDispose( theWin );
  1006.     AdjustMenus();
  1007. }
  1008.  
  1009. /*** NEW EDIT WINDOW ***/
  1010. void NewEditWindow( void )
  1011. {
  1012.     EditWindowPtr        dWin;
  1013.     OSStatus            error;
  1014.     short                refNum = 0;    // 05/10/01 - GAB: NULL is a pointer type, and doesn't fit in a short
  1015. //LR 175    Point                where = { -1, -1 };
  1016.     FSSpec                workSpec;
  1017. // LR: 1.5    Rect                r, offRect;
  1018.  
  1019.     // Get the Template & Create the Window, initially set to the file's data fork
  1020.  
  1021.     dWin = (EditWindowPtr) NewPtrClear( sizeof(EditWindowRecord) );
  1022.     if( !dWin )
  1023.     {
  1024.         FSClose( refNum );
  1025.         ErrorAlert( ES_Caution, errMemory );
  1026.         return;
  1027.     }
  1028.  
  1029.     dWin->fork = FT_Data;
  1030.     dWin->fileSize = 0L;
  1031.     dWin->refNum = 0;
  1032.  
  1033.     // Initialize WorkSpec
  1034.     workSpec = dWin->workSpec;
  1035.     error = FindFolder( kOnSystemDisk, kTemporaryFolderType, kCreateFolder, &workSpec.vRefNum, &workSpec.parID );
  1036.     if( error != noErr )
  1037.     {
  1038.         ErrorAlert( ES_Caution, errFindFolder, error );
  1039.         return;
  1040.     }
  1041.     GetIndString( workSpec.name, strFiles, FN_Untitled );
  1042. //LR: 1.66    BlockMove( "\pUntitledw", workSpec.name, 10 );
  1043.     _ensureNameIsUnique( &workSpec );
  1044. //LR 175    HCreate( workSpec.vRefNum, workSpec.parID, workSpec.name, kAppCreator, '????' );
  1045.     error = FSpCreate( &workSpec, kAppCreator, '????', smSystemScript );
  1046.     if( error != noErr )
  1047.     {
  1048.         ErrorAlert( ES_Caution, errCreate, error );
  1049.         return;
  1050.     }
  1051. //LR 175    error = HOpenDF( workSpec.vRefNum, workSpec.parID, workSpec.name, fsRdWrPerm, &refNum );
  1052.     error = FSpOpenDF( &workSpec, fsRdWrPerm, &refNum );
  1053.     if( error != noErr )
  1054.     {
  1055.         ErrorAlert( ES_Caution, errOpen, error );
  1056.         return;
  1057.     }
  1058.  
  1059.     dWin->workSpec = dWin->fsSpec = workSpec;
  1060.     dWin->workRefNum = refNum;
  1061.     dWin->workBytesWritten = 0L;
  1062.  
  1063.     dWin->fileType = kDefaultFileType;
  1064.     dWin->creator = kAppCreator;
  1065.     dWin->creationDate = 0L;
  1066.  
  1067.     _setupNewEditWindow( dWin, kWindowNormal );    //LR 1.66 "\pUntitled" );    // LR: 1.5 -make mashortenence easier!
  1068.  
  1069.     dWin->firstChunk = NewChunk( 0L, 0L, 0L, CT_Unwritten );
  1070.     dWin->curChunk = dWin->firstChunk;
  1071. }
  1072.  
  1073. #pragma mark -
  1074.  
  1075. // Locate Edit Window    ( LR 951121 )
  1076. // 
  1077. // ENTRY:    File's refnum of Edit theWin to find, and fork open ( -1 == ignore fork )
  1078. //     EXIT:    ptr to edit theWin, or NULL if not found
  1079.  
  1080. EditWindowPtr LocateEditWindow( FSSpec *fs, short fork )
  1081. {
  1082.     WindowRef theWin = FrontNonFloatingWindow();
  1083.  
  1084.     while( theWin )
  1085.     {
  1086.         if( kHexEditWindowTag == GetWindowKind( theWin ) )    // LR: v1.6.5 fix search
  1087.         {
  1088.             EditWindowPtr dWin = (EditWindowPtr)GetWRefCon( theWin );
  1089.  
  1090.             if( dWin && (fork < 0 || dWin->fork == fork) )    // simple checks
  1091.             {
  1092.                 if( EqualString( fs->name, dWin->fsSpec.name, false, true ) &&
  1093.                         fs->vRefNum == dWin->fsSpec.vRefNum && fs->parID == dWin->fsSpec.parID )    // tedious, but only way…
  1094.                     return dWin;
  1095.             }
  1096.         }
  1097.         theWin = GetNextWindow( theWin );
  1098.     }
  1099.     return NULL;
  1100. }
  1101.  
  1102. /*** FIND NEXT EDIT WINDOW ***/
  1103. // NP 177 -- Added FineNextEditWindow, FindFirst calls w/NULL for first window
  1104.  
  1105. EditWindowPtr FindNextEditWindow( EditWindowPtr curr )
  1106. {
  1107.     WindowRef theWin, editWin = NULL;
  1108.  
  1109.     // Find and Select Top Window
  1110.     //LR: 1.66 total re-write to avoid null window references!
  1111.  
  1112.     if( ! curr )
  1113.     theWin = FrontNonFloatingWindow();
  1114.     else
  1115.         theWin =  GetNextWindow( curr->oWin.theWin );
  1116.     
  1117.     if( theWin ) do
  1118.     {
  1119.         if( GetWindowKind( theWin ) == kHexEditWindowTag )
  1120.             editWin = theWin;
  1121.  
  1122.         theWin = GetNextWindow( theWin );
  1123.  
  1124.     }while( theWin && !editWin  );
  1125.  
  1126.     if( !editWin )
  1127.         return( NULL );
  1128.  
  1129.     return( (EditWindowPtr)GetWRefCon( editWin ) );
  1130. }
  1131.  
  1132. /*** FIND FIRST EDIT WINDOW ***/
  1133. EditWindowPtr FindFirstEditWindow( void )
  1134. {
  1135.     return FindNextEditWindow( NULL );
  1136. }
  1137.  
  1138. /*** UPDATE EDIT WINDOWS ***/
  1139. //LR: 1.66 - avoid NULL window ref, DrawPage with CURRENT dWin (not first!)
  1140. void UpdateEditWindows( void )
  1141. {
  1142.     WindowRef        theWin = FrontNonFloatingWindow();
  1143.     EditWindowPtr    dWin;
  1144.  
  1145.     while( theWin )
  1146.     {
  1147.         long windowKind = GetWindowKind( theWin );
  1148.         if( windowKind == kHexEditWindowTag )
  1149.         {
  1150.             dWin = (EditWindowPtr)GetWRefCon( theWin );
  1151. //LR 180            DrawPage( dWin );
  1152.             UpdateOnscreen( theWin );
  1153.         }
  1154.         theWin = GetNextWindow( theWin );
  1155.     }
  1156. }
  1157.  
  1158. /*** MY ACTIVATE ***/
  1159. void MyActivate( WindowRef theWin, Boolean active )
  1160. {
  1161.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  1162.  
  1163.     if( dWin->vScrollBar )
  1164.         HiliteControl( dWin->vScrollBar, active? 0 : 255 );
  1165.     DefaultActivate( theWin, active );
  1166. }
  1167.  
  1168. #pragma mark -
  1169.  
  1170. /*** OFFSET SELECTION ***/
  1171. static void _offsetSelection( EditWindowPtr dWin, short offset, Boolean shiftFlag )
  1172. {
  1173. //LR 180    long    selWidth;
  1174. //LR 180    Boolean    fullUpdate;
  1175.  
  1176. //LR 180    selWidth = dWin->endSel - dWin->startSel;
  1177. //LR 180    fullUpdate = shiftFlag || selWidth > 1;
  1178.  
  1179.     if( offset < 0 )
  1180.     {
  1181.         if( dWin->startSel > 0 )
  1182.         {
  1183.             if( (short) 0xFEED == offset )    // LR: v1.6.5 LR    -"special code"
  1184.                 dWin->startSel = 0;
  1185.             else
  1186.                 dWin->startSel += offset;
  1187.  
  1188.             if( dWin->startSel < 0 )
  1189.                 dWin->startSel = 0;
  1190.             if( !shiftFlag )
  1191.             {
  1192.                 dWin->endSel = dWin->startSel;
  1193.                 CursorOff( dWin->oWin.theWin );
  1194.             }
  1195.             if( !shiftFlag )
  1196.                 CursorOn( dWin->oWin.theWin );
  1197.         }
  1198.         else
  1199.         {
  1200.             SysBeep( 1 );
  1201.             if( !shiftFlag )
  1202.                 dWin->endSel = dWin->startSel;        //LR 1.72 -- deselect anyway
  1203.         }
  1204.         ScrollToSelection( dWin, dWin->startSel, false );
  1205.     }
  1206.     else
  1207.     {
  1208.         if( dWin->endSel < dWin->fileSize )
  1209.         {
  1210.             if( 0xBED == offset )    // LR: v1.6.5 LR    -"special code"
  1211.                 dWin->endSel = dWin->fileSize;
  1212.             else
  1213.                 dWin->endSel += offset;
  1214.  
  1215.             if( dWin->endSel > dWin->fileSize )
  1216.                 dWin->endSel = dWin->fileSize;
  1217.             if( !shiftFlag )
  1218.             {
  1219.                 dWin->startSel = dWin->endSel;
  1220.                 CursorOff( dWin->oWin.theWin );
  1221.             }
  1222.             if( !shiftFlag )
  1223.                 CursorOn( dWin->oWin.theWin );
  1224.         }
  1225.         else
  1226.         {
  1227.             SysBeep( 1 );
  1228.             if( !shiftFlag )
  1229.                 dWin->startSel = dWin->endSel;        //LR 1.72 -- deselect anyway
  1230.         }
  1231.         ScrollToSelection( dWin, dWin->endSel, false );
  1232.     }
  1233. }
  1234.  
  1235. //LR 185 -- macros to ease playing with hiliting
  1236. //#define SETHILITE()    {char c = LMGetHiliteMode(); BitClr( &c, pHiliteBit ); LMSetHiliteMode( c ); }
  1237. //#define SETHILITE()
  1238. //#define HILITERECT(r) SETHILITE(); InvertRect(r)
  1239.  
  1240. #define HILITERECT(r) {    RGBForeColor( &hColor ); PenMode( adMin ); PaintRect(r); RGBForeColor( &grey ); PenMode( srcCopy ); }
  1241. //#define HILITERECT(r) {    RGBForeColor( &hColor ); PenMode( blend ); PaintRect(r); RGBForeColor( &grey ); PenMode( srcCopy ); }
  1242.  
  1243. /*** INVERT SELECTION ***/
  1244. //LR 180 -- changes to draw offscreen instead of directly to window
  1245. static void _hiliteSelection( EditWindowPtr    dWin )
  1246. {
  1247.     Rect    r;
  1248.     long    start, end;
  1249.     short    startX, endX;
  1250.     Boolean    frontFlag;
  1251.     RGBColor hColor, opcolor = { 0x8000, 0x8000, 0xF000 };
  1252. //185    RGBColor invertColor;
  1253.  
  1254.     frontFlag = (dWin->oWin.theWin == FrontNonFloatingWindow() && dWin->oWin.active);
  1255.  
  1256.     if( dWin->endSel <= dWin->startSel )
  1257.         return;
  1258.  
  1259.     GetPortHiliteColor( GetWindowPort( dWin->oWin.theWin ), &hColor );
  1260.  
  1261.     // Set our colors
  1262.     if( ctHdl )
  1263.         RGBBackColor( &(*ctHdl)->body );
  1264.  
  1265.     RGBForeColor( &grey );
  1266.     OpColor( &opcolor );
  1267. /*185
  1268.     if( ctHdl )
  1269.         invertColor = ( *ctHdl )->body;
  1270.     else
  1271.         invertColor = white;
  1272.     
  1273.     InvertColor( &invertColor );
  1274. */    
  1275.     start = dWin->startSel - dWin->editOffset;
  1276.     if( start < 0 )
  1277.         start = 0;
  1278.     end = ( dWin->endSel-1 ) - dWin->editOffset;
  1279.     if( end > ( (dWin->linesPerPage + 1) * kBytesPerLine )-1 )
  1280.         end = ( (dWin->linesPerPage + 1) * kBytesPerLine )-1;
  1281.     
  1282.     startX = COLUMN( start );
  1283.     endX = COLUMN( end );
  1284.     
  1285.     // Are we the frontmost window? (ie, draw filled selection)
  1286.     if( frontFlag )
  1287.     {
  1288.         if( dWin->editMode == EM_Hex )    // color hex area?
  1289.         {
  1290.             if( LINENUM( start ) < LINENUM( end ) )    // yes, do we have more than one line?
  1291.             {
  1292.                 // Invert Hex
  1293.                 r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight;
  1294.                 r.bottom = r.top + kLineHeight;
  1295.                 r.left = kDataDrawPos + HEXPOS( startX ) - 3;
  1296.                 r.right = kDataDrawPos + HEXPOS( kBytesPerLine ) - 3;
  1297.                 HILITERECT( &r );
  1298.  
  1299.                 // Outline Box around Ascii
  1300.                 r.left = kTextDrawPos + CHARPOS( startX ) - 1;
  1301.                 r.right = kTextDrawPos + CHARPOS( kBytesPerLine );
  1302.                 
  1303.                 MoveTo( kTextDrawPos, r.bottom );
  1304.                 LineTo( r.left, r.bottom );
  1305.     
  1306.                 LineTo( r.left, r.top );
  1307.                 if( dWin->startSel >= dWin->editOffset )
  1308.                     LineTo( r.right, r.top );
  1309.                 else
  1310.                     MoveTo( r.right, r.top );
  1311.                 LineTo( r.right, r.bottom );
  1312.     
  1313.                 // Invert Hex portion block (ie, multiple lines)
  1314.                 if( LINENUM( start ) < LINENUM( end )-1 )
  1315.                 {
  1316.                     r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight + kLineHeight;
  1317.                     r.bottom = /*(kHeaderHeight / 2) +*/ LINENUM( end ) * kLineHeight;
  1318.                     r.left = kDataDrawPos - 3;
  1319.                     r.right = kDataDrawPos + HEXPOS( kBytesPerLine ) - 3;
  1320.                     HILITERECT( &r );
  1321.     
  1322.                     r.left = kTextDrawPos - 1;
  1323.                     r.right = kTextDrawPos + CHARPOS( kBytesPerLine );
  1324.                     MoveTo( r.left, r.top );
  1325.                     LineTo( r.left, r.bottom );
  1326.                     MoveTo( r.right, r.top );
  1327.                     LineTo( r.right, r.bottom );
  1328.                 }
  1329.                 r.top = /*(kHeaderHeight / 2) +*/ LINENUM( end ) * kLineHeight;
  1330.                 r.bottom = r.top + kLineHeight;
  1331.                 r.left = kDataDrawPos - 3;
  1332.                 r.right = kDataDrawPos + HEXPOS( endX ) + kHexWidth - 3;
  1333.                 HILITERECT( &r );
  1334.     
  1335.                 r.left = kTextDrawPos - 1;
  1336.                 r.right = kTextDrawPos + CHARPOS( endX ) + kCharWidth;    //LR 180 - 1;
  1337.                 MoveTo( r.left, r.top );
  1338.                 LineTo( r.left, r.bottom-1 );
  1339.                 if( dWin->endSel < dWin->editOffset + dWin->linesPerPage * kBytesPerLine )
  1340.                 {
  1341.                     LineTo( r.right, r.bottom-1 );
  1342.                 }
  1343.                 else
  1344.                     MoveTo( r.right, r.bottom-1 );
  1345.                 LineTo( r.right, r.top );
  1346.                 LineTo( kTextDrawPos + CHARPOS( kBytesPerLine ), r.top );
  1347.             }
  1348.             else    // we only have a single line or less!
  1349.             {
  1350.                 r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight;
  1351.                 r.bottom = r.top + kLineHeight;
  1352.                 r.left = kDataDrawPos + HEXPOS( startX ) - 3;
  1353.                 r.right = kDataDrawPos + HEXPOS( endX ) + kHexWidth - 3;
  1354.                 HILITERECT( &r );
  1355.     
  1356.                 r.left = kTextDrawPos + CHARPOS( startX )-1;
  1357.                 r.right = kTextDrawPos + CHARPOS( endX ) + kCharWidth;    //LR 180 - 1;
  1358.     
  1359.                 MoveTo( r.left, r.top );
  1360.                 LineTo( r.left, r.bottom-1 );
  1361.                 if( dWin->endSel < dWin->editOffset + dWin->linesPerPage * kBytesPerLine )
  1362.                 {
  1363.                     LineTo( r.right, r.bottom-1 );
  1364.                 }
  1365.                 else
  1366.                     MoveTo( r.right, r.bottom-1 );
  1367.                 LineTo( r.right, r.top );
  1368.                 if( dWin->startSel >= dWin->editOffset )
  1369.                 {
  1370.                     LineTo( r.left, r.top );
  1371.                 }
  1372.             }
  1373.         }
  1374.         else    // color in the ASCII area
  1375.         {
  1376.             if( LINENUM( start ) < LINENUM( end ) )        // more than one line?
  1377.             {
  1378.                 // Outline Hex
  1379.                 r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight;
  1380.                 r.bottom = r.top + kLineHeight;
  1381.                 r.left = kDataDrawPos + HEXPOS( startX ) - 3;
  1382.                 r.right = kDataDrawPos + HEXPOS( kBytesPerLine ) - 3;
  1383.     
  1384.                 MoveTo( kDataDrawPos - 3, r.bottom );
  1385.                 LineTo( r.left, r.bottom );
  1386.                 LineTo( r.left, r.top );
  1387.                 if( dWin->startSel >= dWin->editOffset )
  1388.                 {
  1389.                     LineTo( r.right, r.top );
  1390.                 }
  1391.                 else
  1392.                     MoveTo( r.right, r.top );
  1393.                 LineTo( r.right, r.bottom );
  1394.     
  1395.                 // Invert Ascii
  1396.                 r.left = kTextDrawPos + CHARPOS( startX ) - 1;
  1397.                 r.right = kTextDrawPos + CHARPOS( kBytesPerLine );
  1398.                 HILITERECT( &r );
  1399.     
  1400.                 if( LINENUM( start ) < LINENUM( end )-1 )
  1401.                 {
  1402.                     r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight + kLineHeight;
  1403.                     r.bottom = /*(kHeaderHeight / 2) +*/ LINENUM( end ) * kLineHeight;
  1404.                     r.left = kDataDrawPos - 3;
  1405.                     r.right = kDataDrawPos + HEXPOS( kBytesPerLine ) - 3;
  1406.                     MoveTo( r.left, r.top );
  1407.                     LineTo( r.left, r.bottom );
  1408.                     MoveTo( r.right, r.top );
  1409.                     LineTo( r.right, r.bottom );
  1410.     
  1411.                     r.left = kTextDrawPos - 1;
  1412.                     r.right = kTextDrawPos + CHARPOS( kBytesPerLine );
  1413.                     HILITERECT( &r );
  1414.                 }
  1415.                 r.top = /*(kHeaderHeight / 2) +*/ LINENUM( end ) * kLineHeight;
  1416.                 r.bottom = r.top + kLineHeight;
  1417.                 r.left = kDataDrawPos - 3;
  1418.                 r.right = kDataDrawPos + HEXPOS( endX ) + kHexWidth - 3;
  1419.                 MoveTo( r.left, r.top );
  1420.                 LineTo( r.left, r.bottom );
  1421.                 if( dWin->endSel < dWin->editOffset + dWin->linesPerPage * kBytesPerLine )
  1422.                 {
  1423.                     LineTo( r.right, r.bottom );
  1424.                 }
  1425.                 else
  1426.                     MoveTo( r.right, r.bottom );
  1427.                 LineTo( r.right, r.top );
  1428.                 LineTo( kDataDrawPos + HEXPOS( kBytesPerLine ) - 3, r.top );
  1429.     
  1430.                 r.left = kTextDrawPos - 1;
  1431.                 r.right = kTextDrawPos + CHARPOS( endX ) + kCharWidth;    //LR 180 - 1;
  1432.                 HILITERECT( &r );
  1433.             }
  1434.             else    // one line only
  1435.             {
  1436.                 r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight;
  1437.                 r.bottom = r.top + kLineHeight;
  1438.                 r.left = kDataDrawPos + HEXPOS( startX ) - 3;
  1439.                 r.right = kDataDrawPos + HEXPOS( endX ) + kHexWidth - 3;
  1440.                 MoveTo( r.left, r.top );
  1441.                 LineTo( r.left, r.bottom );
  1442.                 if( dWin->endSel < dWin->editOffset + dWin->linesPerPage * kBytesPerLine )
  1443.                 {
  1444.                     LineTo( r.right, r.bottom );
  1445.                 }
  1446.                 else
  1447.                     MoveTo( r.right, r.bottom );
  1448.                 LineTo( r.right, r.top );
  1449.                 if( dWin->startSel >= dWin->editOffset )
  1450.                 {
  1451.                     LineTo( r.left, r.top );
  1452.                 }
  1453.     
  1454.                 r.left = kTextDrawPos + CHARPOS( startX ) - 1;
  1455.                 r.right = kTextDrawPos + CHARPOS( endX ) + kCharWidth;
  1456.                 HILITERECT( &r );
  1457.             }
  1458.         }
  1459.     }
  1460.     else    // We are in the background
  1461.     {
  1462.         if( LINENUM( start ) < LINENUM( end ) )
  1463.         {
  1464.             // Outline Hex
  1465.             r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight;
  1466.             r.bottom = r.top + kLineHeight;
  1467.             r.left = kDataDrawPos + HEXPOS( startX ) - 3;
  1468.             r.right = kDataDrawPos + HEXPOS( kBytesPerLine ) - 3;
  1469.  
  1470.             MoveTo( kDataDrawPos - 3, r.bottom );
  1471.             LineTo( r.left, r.bottom );
  1472.             LineTo( r.left, r.top );
  1473.             if( dWin->startSel >= dWin->editOffset )
  1474.             {
  1475.                 LineTo( r.right, r.top );
  1476.             }
  1477.             else
  1478.                 MoveTo( r.right, r.top );
  1479.             LineTo( r.right, r.bottom );
  1480.  
  1481.             // Outline Box around Ascii
  1482.             r.left = kTextDrawPos + CHARPOS( startX ) - 1;
  1483.             r.right = kTextDrawPos + CHARPOS( kBytesPerLine );
  1484.             
  1485.             MoveTo( kTextDrawPos, r.bottom );
  1486.             LineTo( r.left, r.bottom );
  1487.  
  1488.             LineTo( r.left, r.top );
  1489.             if( dWin->startSel >= dWin->editOffset )
  1490.                 LineTo( r.right, r.top );
  1491.             else
  1492.                 MoveTo( r.right, r.top );
  1493.             LineTo( r.right, r.bottom );
  1494.  
  1495.             if( LINENUM( start ) < LINENUM( end ) - 1 )
  1496.             {
  1497.                 r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight + kLineHeight;
  1498.                 r.bottom = /*(kHeaderHeight / 2) +*/ LINENUM( end ) * kLineHeight;
  1499.                 r.left = kDataDrawPos - 3;
  1500.                 r.right = kDataDrawPos + HEXPOS( kBytesPerLine ) - 3;
  1501.                 MoveTo( r.left, r.top );
  1502.                 LineTo( r.left, r.bottom );
  1503.                 MoveTo( r.right, r.top );
  1504.                 LineTo( r.right, r.bottom );
  1505.  
  1506.                 r.left = kTextDrawPos - 1;
  1507.                 r.right = kTextDrawPos + CHARPOS( kBytesPerLine );
  1508.                 MoveTo( r.left, r.top );
  1509.                 LineTo( r.left, r.bottom );
  1510.                 MoveTo( r.right, r.top );
  1511.                 LineTo( r.right, r.bottom );
  1512.             }
  1513.             r.top = /*(kHeaderHeight / 2) +*/ LINENUM( end ) * kLineHeight;
  1514.             r.bottom = r.top + kLineHeight;
  1515.             r.left = kDataDrawPos - 3;
  1516.             r.right = kDataDrawPos + HEXPOS( endX ) + kHexWidth - 3;
  1517.             MoveTo( r.left, r.top );
  1518.             LineTo( r.left, r.bottom );
  1519.             if( dWin->endSel < dWin->editOffset + dWin->linesPerPage * kBytesPerLine )
  1520.                 LineTo( r.right, r.bottom );
  1521.             else
  1522.                 MoveTo( r.right, r.bottom );
  1523.             LineTo( r.right, r.top );
  1524.             LineTo( kDataDrawPos + HEXPOS( kBytesPerLine ) - 3, r.top );
  1525.  
  1526.             r.left = kTextDrawPos - 1;
  1527.             r.right = kTextDrawPos + CHARPOS( endX ) + kCharWidth - 1;
  1528.             MoveTo( r.left, r.top );
  1529.             LineTo( r.left, r.bottom-1 );
  1530.             if( dWin->endSel < dWin->editOffset + dWin->linesPerPage * kBytesPerLine )
  1531.                 LineTo( r.right, r.bottom-1 );
  1532.             else
  1533.                 MoveTo( r.right, r.bottom-1 );
  1534.             LineTo( r.right, r.top );
  1535.             LineTo( kTextDrawPos + CHARPOS( kBytesPerLine ), r.top );
  1536.         }
  1537.         else
  1538.         {
  1539.             r.top = /*(kHeaderHeight / 2) +*/ LINENUM( start ) * kLineHeight;
  1540.             r.bottom = r.top + kLineHeight;
  1541.             r.left = kDataDrawPos + HEXPOS( startX ) - 3;
  1542.             r.right = kDataDrawPos + HEXPOS( endX ) + kHexWidth - 3;
  1543.             MoveTo( r.left, r.top );
  1544.             LineTo( r.left, r.bottom );
  1545.             if( dWin->endSel < dWin->editOffset + dWin->linesPerPage * kBytesPerLine )
  1546.                 LineTo( r.right, r.bottom );
  1547.             else
  1548.                 MoveTo( r.right, r.bottom );
  1549.             LineTo( r.right, r.top );
  1550.             if( dWin->startSel >= dWin->editOffset )
  1551.                 LineTo( r.left, r.top );
  1552.  
  1553.             r.left = kTextDrawPos + CHARPOS( startX )-1;
  1554.             r.right = kTextDrawPos + CHARPOS( endX ) + kCharWidth - 1;
  1555.  
  1556.             MoveTo( r.left, r.top );
  1557.             LineTo( r.left, r.bottom-1 );
  1558.             if( dWin->endSel < dWin->editOffset + dWin->linesPerPage * kBytesPerLine )
  1559.             {
  1560.                 LineTo( r.right, r.bottom-1 );
  1561.             }
  1562.             else
  1563.                 MoveTo( r.right, r.bottom-1 );
  1564.             LineTo( r.right, r.top );
  1565.             if( dWin->startSel >= dWin->editOffset )
  1566.             {
  1567.                     LineTo( r.left, r.top );
  1568.             }
  1569.         }
  1570.     }
  1571.  
  1572.     //LR 185 -- Ensure normal draws after we are done!
  1573.     if( ctHdl )
  1574.         RGBBackColor( &white );
  1575.  
  1576.     RGBForeColor( &black );
  1577. //    PenMode( srcCopy );
  1578. }
  1579.  
  1580. /*** INIT COLOUR TABLE ***/
  1581. static OSStatus _initColorTable( HEColorTablePtr ct )
  1582. {
  1583.     ct->header.red = ct->header.green = ct->header.blue =    // default light grey scheme
  1584.     ct->bar.red = ct->bar.green = ct->bar.blue = 0xCFFF;
  1585.     ct->headerLine.red = ct->headerLine.green = ct->headerLine.blue =
  1586.     ct->barLine.red = ct->barLine.green = ct->barLine.blue = 0x7FFF;
  1587.     ct->headerText = ct->barText = ct->text = black;
  1588.     ct->body = white;
  1589.     ct->bodyDark = white;
  1590.     return noErr;
  1591. }
  1592.  
  1593. /*** GET COLOUR INFO ***/
  1594. static OSStatus _getColorInfo( EditWindowPtr dWin )
  1595. {
  1596.     // NS: 1.3, set hilight colour
  1597. /*    Handle vars = dWin->oWin.theWin.port.grafVars;
  1598.     RGBColor hilightColour = (** (GVarHandle) vars).rgbHiliteColor;
  1599.     RGBColor rgbBlack = { nixBlack, nixBlack, nixBlack };
  1600.     RGBForeColor( &hilightColour );
  1601. */    
  1602.     if( gPrefs.useColor && dWin->csResID > 0 )
  1603.     {
  1604.         ctHdl = (HEColorTableHandle) GetResource( 'HEct', dWin->csResID );
  1605.         if( !ctHdl )
  1606.         {
  1607.             ctHdl = (HEColorTableHandle) NewHandle( sizeof(HEColorTable_t) );
  1608.             if( ctHdl ) _initColorTable( *ctHdl );
  1609.         }
  1610.     }
  1611.     else ctHdl = NULL;    // LR: all that's needed to be nonQD compatible?
  1612.     return noErr;
  1613. }
  1614.  
  1615. /*** DRAW HEADER ***/
  1616. static void _drawHeader( EditWindowPtr dWin, Rect *r )
  1617. {
  1618.     char str[256];    //LR 1.7 -- no need for fork, replaced with selection length, str2[31];
  1619.  
  1620.     _getColorInfo( dWin );    // LR: v1.6.5 ensure that updates are valid!
  1621.  
  1622.     TextFont( g.fontFaceID );
  1623.     TextSize( g.fontSize );
  1624.     TextFace( normal );    // LR: v1.6.5 LR - can't be bold 'cause then the new stuff doesn fit :0
  1625.     TextMode( srcCopy );
  1626.  
  1627.     // LR: if we have color table, fill in the address bar!
  1628.     if( ctHdl )
  1629.     {
  1630.         RGBBackColor( &( *ctHdl )->header );
  1631.         RGBForeColor( &( *ctHdl )->headerLine );
  1632.     }
  1633.     else
  1634.     {
  1635.         RGBForeColor( &black );
  1636.         RGBBackColor( &white );
  1637.     }
  1638.  
  1639.     EraseRect( r );    // uses back color
  1640.  
  1641.     r->right -= kSBarSize;    // LR: v1.6.5 don't overwrite scroll bar icon
  1642.  
  1643.     MoveTo( r->left, r->bottom );    // LR: 1.7 - only one line, darker above scroll bar looked bogus
  1644.     LineTo( r->right, r->bottom );    // uses fore color
  1645.  
  1646.     if( ctHdl )
  1647.         RGBForeColor( &( *ctHdl )->headerText );
  1648.  
  1649.     // LR: v1.6.5 LR - more stuff in the header now & strings are from an localizable resource :)
  1650.  
  1651.     /* NS note to self:    %8    is length of eight (pads with spaces)
  1652.                         %08    is length of eight (pads with zeros)
  1653.                         %l    makes the number a long
  1654.                         %d    identifies as a number (decimal)
  1655.                         %X    identifies as a number (hexadecimal)        */
  1656.     
  1657.     GetIndString( (StringPtr) str, strHeader, gPrefs.decimalAddr? HD_Decimal : HD_Hex );
  1658.     CopyPascalStringToC( (StringPtr) str, str );
  1659. //1.7    GetIndString( (StringPtr) str2, strHeader, dWin->fork );
  1660. //1.7    CopyPascalStringToC( (StringPtr) str2, str2 );
  1661.     sprintf( (char *) g.buffer, str, dWin->fileSize, &dWin->fileType, &dWin->creator, /*str2,*/ dWin->startSel, dWin->endSel, dWin->endSel - dWin->startSel );
  1662.     MoveTo( 5, r->top + kLineHeight );
  1663.     DrawText( g.buffer, 0, strlen( (char *) g.buffer ) );
  1664.     
  1665.     if( ctHdl )    // reset colors to known state
  1666.     {
  1667.         RGBForeColor( &black );
  1668.         RGBBackColor( &white );
  1669.     }
  1670. }
  1671.  
  1672. /*** DrawFooter ***/
  1673. // only used when printing
  1674. // LR: 1.7 - use TextUtils to get date/time strings in user preferred format!
  1675. static void _drawFooter( EditWindowPtr dWin, Rect *r, short pageNbr, short nbrPages )
  1676. {
  1677.     unsigned long    dt;
  1678.     Str63    s1, s2;
  1679.  
  1680.     TextFont( g.fontFaceID );
  1681.     TextSize( g.fontSize );
  1682.     TextFace( normal );
  1683.     TextMode( srcCopy );
  1684.  
  1685.     // LR: 1.7 - if we have color table, fill in the address bar!
  1686.     if( ctHdl )
  1687.     {
  1688.         RGBBackColor( &( *ctHdl )->header );
  1689.         RGBForeColor( &( *ctHdl )->headerLine );
  1690.     }
  1691.     else
  1692.     {
  1693.         RGBForeColor( &black );
  1694.         RGBBackColor( &white );
  1695.     }
  1696.  
  1697.     // Draw seperator line (seperates footer from body)
  1698.     MoveTo( r->left, r->top );
  1699.     LineTo( r->right, r->top );
  1700.  
  1701.     if( ctHdl )
  1702.         RGBForeColor( &( *ctHdl )->headerText );
  1703.  
  1704.     // Draw Date & Time on left edge of footer
  1705.     GetDateTime( &dt );
  1706.     DateString( dt, abbrevDate, s1, NULL );    //LR: 1.7 - get date/time strings as users wants them
  1707.     TimeString( dt, false, s2, NULL );
  1708.     sprintf( (char *)g.buffer, "%.*s %.*s", (int)s1[0], (char *)&s1[1], (int)s2[0], (char *)&s2[1] );
  1709.     MoveTo( 10, r->top + kLineHeight );
  1710.     DrawText( g.buffer, 0, strlen( (char *) g.buffer ) );
  1711.  
  1712.     // Draw filename in middle of footer
  1713.     GetIndString( s1, strHeader, HD_Footer );
  1714.     GetWTitle( dWin->oWin.theWin, s2 );
  1715.     sprintf( (char *)g.buffer, "%.*s %.*s", (int)s1[0], (char *)&s1[1], (int)s2[0], (char *)&s2[1] );
  1716.     MoveTo( ( r->left + r->right ) / 2 - TextWidth( g.buffer, 0, strlen((char *)g.buffer )) / 2, r->top + kLineHeight );
  1717.     DrawText( g.buffer, 0, strlen( (char *)g.buffer ) );
  1718.  
  1719.     // Draw page # & count on right edge of footer
  1720.     sprintf( (char *)g.buffer, "%d of %d", pageNbr, nbrPages );
  1721.     MoveTo( r->right - TextWidth( g.buffer, 0, strlen((char *)g.buffer )) - 8, r->top + kLineHeight );
  1722.     DrawText( g.buffer, 0, strlen( (char *)g.buffer ) );
  1723.  
  1724.     if( ctHdl )    // reset colors to known state
  1725.     {
  1726.         RGBForeColor( &black );
  1727.         RGBBackColor( &white );
  1728.     }
  1729. }
  1730.  
  1731. /*** DRAW DUMP ***/
  1732. // Draws the actual hex/decimal and ASCII panes in the window
  1733.  
  1734. // NOTE: the kStringTextPos stuff is a bit weird, but it's because I want to draw the leading space in the body
  1735. //            color instead of the address color (and because we don't print the extra spaces every time).
  1736.  
  1737. static OSStatus _drawDump( EditWindowPtr dWin, Rect *r, long sAddr, long eAddr )
  1738. {
  1739.     short    i, j, y;
  1740.     short    hexPos;
  1741.     short    asciiPos;
  1742.     register short    ch, ch1, ch2;
  1743.     long    addr;
  1744.     Rect addrRect;
  1745.  
  1746.     TextFont( g.fontFaceID );
  1747.     TextSize( g.fontSize );
  1748.     TextFace( normal );
  1749.     TextMode( srcCopy );
  1750.  
  1751.     // create address border bounds rectangle
  1752.     addrRect.top = r->top;    // we need to erase seperating space
  1753.     addrRect.left = r->left;
  1754.     addrRect.right = r->left + kBodyDrawPos + StringWidth( "\p 00000000:" );    //LR 180 -- use 8 chars, not 7!
  1755.     addrRect.bottom = r->bottom;
  1756.  
  1757.     if( ctHdl )
  1758.         RGBBackColor( &( *ctHdl )->bar );
  1759.     EraseRect( &addrRect );
  1760.  
  1761.     addr = sAddr - (sAddr % kBytesPerLine);
  1762.     g.buffer[kStringTextPos - 1] = g.buffer[kStringHexPos - 1] = g.buffer[kStringHexPos + kBodyStrLen] = ' ';
  1763.  
  1764.     // Now, draw each line of data
  1765.     for( y = r->top + (kLineHeight - 2), j = 0; y < r->bottom && addr < eAddr; y += kLineHeight, j++ )
  1766.     {
  1767.         if( gPrefs.decimalAddr )
  1768.             sprintf( (char *)&g.buffer[0], "%9ld:", addr );
  1769.         else
  1770.             sprintf( (char *)&g.buffer[0], " %08lX:", addr );
  1771.  
  1772.         // draw the address (not one big string due to different coloring!)
  1773.         if( ctHdl )
  1774.         {
  1775.             RGBBackColor( &( *ctHdl )->bar );
  1776.             RGBForeColor( &( *ctHdl )->barText );
  1777.         }
  1778.  
  1779.         MoveTo( kBodyDrawPos, y );
  1780.         DrawText( g.buffer, 0, kStringHexPos - 1 );
  1781.  
  1782.         // draw the data (hex and ascii)
  1783.         if( ctHdl )
  1784.         {
  1785.             Rect r2;
  1786.  
  1787.             RGBBackColor( (j & 1) ? &( *ctHdl )->bodyDark : &( *ctHdl )->body );    //LR 180 -- choose appr. body bkgnd color
  1788.             RGBForeColor( &( *ctHdl )->text );
  1789.  
  1790.             // LR: 1.7 -- must erase for this to show up on printouts!
  1791.             r2.top = y - (kLineHeight - 3);
  1792.             r2.left = addrRect.right + 1;
  1793.             r2.bottom = y + 3;
  1794.             r2.right = r->right;
  1795.             EraseRect( &r2 );
  1796.         }
  1797.  
  1798.         hexPos = kStringHexPos;
  1799.         asciiPos = kStringTextPos;
  1800.  
  1801.         for( i = kBytesPerLine; i; --i, ++addr )
  1802.         {
  1803.             if( addr >= sAddr && addr < eAddr )
  1804.             {
  1805.                 ch = GetByte( dWin, addr );
  1806.                 ch1 = ch2 = ch;
  1807.                 ch1 >>= 4;
  1808.                 ch2 &= 0x0F;
  1809.  
  1810. #define SINGLE_DRAW 1
  1811.  
  1812. #if SINGLE_DRAW
  1813.                 g.buffer[hexPos++] = ch1 + (( ch1 < 10 )? '0' : ( 'A'-10 ));
  1814.                 g.buffer[hexPos++] = ch2 + (( ch2 < 10 )? '0' : ( 'A'-10 ));
  1815.                 g.buffer[hexPos++] = ' ';
  1816.                 g.buffer[asciiPos++] = (ch >= 0x20 && ch <= g.highChar && 0x7F != ch) ? ch : '.';    // LR: 1.7 - 0x7F doesn't draw ANYTHING! Ouch!
  1817. #else
  1818.                 g.buffer[0] = ch1 + (( ch1 < 10 )? '0' : ( 'A'-10 ));
  1819.                 g.buffer[1] = ch2 + (( ch2 < 10 )? '0' : ( 'A'-10 ));
  1820.                 g.buffer[2] = ' ';
  1821.                 g.buffer[4] = (ch >= 0x20 && ch <= g.highChar && 0x7F != ch) ? ch : '.';    // LR: 1.7 - 0x7F doesn't draw ANYTHING! Ouch!
  1822. #endif
  1823.             }
  1824.             else
  1825.             {
  1826. #if SINGLE_DRAW
  1827.                 g.buffer[hexPos++] = ' ';
  1828.                 g.buffer[hexPos++] = ' ';
  1829.                 g.buffer[hexPos++] = ' ';
  1830.                 g.buffer[asciiPos++] = ' ';
  1831. #else
  1832.                 g.buffer[0] = ' ';
  1833.                 g.buffer[1] = ' ';
  1834.                 g.buffer[2] = ' ';
  1835.                 g.buffer[4] = ' ';
  1836. #endif
  1837.             }
  1838. #if !SINGLE_DRAW
  1839.             MoveTo( kDataDrawPos - kHexWidth + (kHexWidth * i), y );
  1840.             DrawText( g.buffer, 0, 3 );
  1841.             MoveTo( kTextDrawPos + (kCharWidth * i), y );
  1842.             DrawText( g.buffer, 4, 1 );
  1843. #endif
  1844.         }
  1845.  
  1846.         // %% NOTE: Carsten says to move this into for loop (ie, draw each byte's data) to
  1847.         //            prevent font smoothing from messing up the spacing
  1848. #if SINGLE_DRAW
  1849.         MoveTo( kDataDrawPos - kCharWidth, y );
  1850.         DrawText( g.buffer, kStringHexPos - 1, kBodyStrLen + 3 );
  1851. #endif
  1852.     }
  1853.  
  1854.     // Draw left edging? (line only, background erases, but line is erased by text!)
  1855.     if( ctHdl )
  1856.     {
  1857. //LR 1.7        RGBBackColor( &( *ctHdl )->bar );
  1858.         RGBForeColor( &( *ctHdl )->barLine );
  1859.  
  1860. //LR 1.7 - moved above        EraseRect( &addrRect );
  1861.  
  1862.         MoveTo( addrRect.right, addrRect.top );
  1863.         LineTo( addrRect.right, addrRect.bottom );
  1864.     }
  1865.  
  1866.     // Draw vertical bars?
  1867.     // based on David Emme's vertical bar mod
  1868.     if( gPrefs.vertBars )
  1869.     {
  1870.         if( ctHdl )
  1871.             RGBForeColor( &( *ctHdl )->dividerLine );    //LR 181 -- now had it's own color!
  1872.  
  1873.         MoveTo( CHARPOS(kStringHexPos + 11) - (kCharWidth / 2) - 1, addrRect.top );
  1874.         LineTo( CHARPOS(kStringHexPos + 11) - (kCharWidth / 2) - 1, addrRect.bottom );
  1875.  
  1876.         MoveTo( CHARPOS(kStringHexPos + 23) - (kCharWidth / 2) - 1, addrRect.top );
  1877.         LineTo( CHARPOS(kStringHexPos + 23) - (kCharWidth / 2) - 1, addrRect.bottom );
  1878.  
  1879.         MoveTo( CHARPOS(kStringHexPos + 35) - (kCharWidth / 2) - 1, addrRect.top );
  1880.         LineTo( CHARPOS(kStringHexPos + 35) - (kCharWidth / 2) - 1, addrRect.bottom );
  1881.     }
  1882.  
  1883.     // LR: restore color
  1884.     if( ctHdl )
  1885.     {
  1886.         RGBForeColor( &black );
  1887.         RGBBackColor( &white );
  1888.     }
  1889.     return noErr;
  1890. }
  1891.  
  1892. /*** DRAW PAGE ***/
  1893. static void _drawPage( EditWindowPtr dWin )
  1894. {
  1895.     GrafPtr            savePort;
  1896.     Rect            r;
  1897.     PixMapHandle    thePixMapH; // sel, for (un)LockPixels
  1898.  
  1899. #if PROFILE
  1900.     _profile = 1;
  1901. #endif
  1902.  
  1903.     _getColorInfo( dWin );    // LR: v1.6.5 multiple routines need this
  1904.  
  1905.     GetPort( &savePort );
  1906.     thePixMapH = GetGWorldPixMap( /*LR 180 dWin->*/ g.offscreen );
  1907.     if ( LockPixels( thePixMapH ) )
  1908.     {
  1909.         SetPort( ( GrafPtr )/*LR 180 dWin->*/ g.offscreen );
  1910.  
  1911.         GetPortBounds( /*LR 180 dWin->*/ g.offscreen, &r );
  1912.  
  1913.         if( ctHdl )
  1914.             RGBBackColor( &( *ctHdl )->body );
  1915.         else
  1916.         {
  1917.             ForeColor( blackColor );
  1918.             BackColor( whiteColor );
  1919.         }
  1920.  
  1921.         // Erase only that part of the buffer that isn't drawn to!
  1922.         if( (dWin->fileSize - dWin->editOffset) / kBytesPerLine <= dWin->linesPerPage )
  1923.         {
  1924.             Rect er = r;
  1925.  
  1926.             er.top = (((dWin->fileSize - dWin->editOffset) / kBytesPerLine) * kLineHeight);    //LR 1.72 -- need line height!
  1927.             if( (dWin->fileSize % kBytesPerLine) )    //LR 1.72 -- if not an empty line, no need to erase current line
  1928.                 er.top += kLineHeight;
  1929.             EraseRect( &er );
  1930.         }
  1931.  
  1932.         _drawDump( dWin, &r, dWin->editOffset, dWin->fileSize );
  1933.  
  1934.         if( ctHdl )
  1935.         {
  1936.             RGBForeColor( &black );
  1937.             RGBBackColor( &white );
  1938.         }
  1939.  
  1940.         //LR: 180 -- we can now draw the selection offscreen since we always do full updates
  1941.         if( dWin->endSel > dWin->startSel && dWin->endSel >= dWin->editOffset && dWin->startSel < dWin->editOffset + (dWin->linesPerPage * kBytesPerLine) )
  1942.             _hiliteSelection( dWin );
  1943.  
  1944.         UnlockPixels( thePixMapH ); // sel
  1945.         SetPort( savePort );
  1946.     }
  1947.  
  1948. #if PROFILE
  1949.     _profile = 0;
  1950. #endif
  1951. }
  1952.  
  1953. /*** UPDATE ONSCREEN ***/
  1954. void UpdateOnscreen( WindowRef theWin )
  1955. {
  1956.     Rect            r1, r2;//, r3;
  1957.     GrafPtr            oldPort;
  1958.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  1959.     PixMapHandle thePixMapH;
  1960.  
  1961.     //LR 180 -- all updates now must draw the entire screen!
  1962.     _drawPage( dWin );
  1963.  
  1964.     // Now, draw the header information
  1965.     thePixMapH = GetPortPixMap( GetWindowPort( theWin ) );
  1966.     if ( LockPixels( thePixMapH ) )
  1967.     {
  1968.         GetPortBounds( /*LR 180 dWin->*/ g.offscreen, &r1 );
  1969.         GetWindowPortBounds( theWin, &r2 );
  1970.  
  1971.         GetPort( &oldPort );
  1972.         SetPortWindowPort( theWin );
  1973.  
  1974.         g.cursorFlag = false;
  1975.  
  1976.         // LR: Header drawn here due to overlapping vScrollBar
  1977.         r2.bottom = r2.top + kHeaderHeight - 1;
  1978.         _drawHeader( dWin, &r2 );
  1979.  
  1980.         // LR: adjust for scrollbar & header
  1981.         GetWindowPortBounds( theWin, &r2 );
  1982. // LR: 1.7        r2.right -= kSBarSize - 1;
  1983. //        r2.top += kHeaderHeight;
  1984. //        SectRect( &r1, &r2, &r3 );
  1985.  
  1986.         // restrict draw height to height of window port!
  1987.         r2.top = kHeaderHeight;
  1988.         r2.right -= kSBarSize;
  1989.         r1.bottom = r1.top + (r2.bottom - r2.top);
  1990.  
  1991.     //LR 160 -- Must blit a bit differently when in Carbon
  1992.  
  1993.     #if TARGET_API_MAC_CARBON
  1994.         CopyBits( GetPortBitMapForCopyBits( /*LR 180 dWin->*/ g.offscreen ), GetPortBitMapForCopyBits( GetWindowPort( theWin ) ), &r1, &r2, srcCopy, 0L );
  1995.     #else
  1996.         CopyBits( ( BitMap * ) &( /*LR 180 dWin->*/ g.offscreen )->portPixMap, &theWin->portBits, &r1, &r2, srcCopy, 0L );
  1997.     #endif
  1998.  
  1999.         //%% LR: 1.7 -- needs to be done offscreen, but then it's  not erased -- this is a new shell todo item :)
  2000. //LR 180        if( dWin->endSel > dWin->startSel && dWin->endSel >= dWin->editOffset && dWin->startSel < dWin->editOffset + (dWin->linesPerPage * kBytesPerLine) )
  2001. //LR 180            _hiliteSelection( dWin );
  2002.  
  2003.         UnlockPixels( thePixMapH );
  2004.         SetPort( oldPort );
  2005.     }
  2006. }
  2007.  
  2008. // Respond to an update event - BeginUpdate has already been called.
  2009.  
  2010. /*** MY DRAW ***/
  2011. void MyDraw( WindowRef theWin )
  2012. {
  2013. //LR 190 --    EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  2014.     DrawControls( theWin );
  2015.  
  2016.     if( !g.useAppearance )    //LR 1.72 -- must call when not using Appearance
  2017.         DrawGrowIcon( theWin );
  2018.  
  2019.     // EraseRect( &theWin->portRect );
  2020. //LR 180    DrawPage( dWin );
  2021.     UpdateOnscreen( theWin );
  2022. }
  2023.  
  2024. /*** MY IDLE ***/
  2025. void MyIdle( WindowRef theWin, EventRecord *er )
  2026. {
  2027.     EditWindowPtr    dWin = (EditWindowPtr)GetWRefCon( theWin );
  2028.  
  2029. // LR: v1.6.5    long            scrapCount;
  2030.     Boolean            frontWindowFlag;
  2031.     Point            w;
  2032.  
  2033.     frontWindowFlag = (theWin == FrontNonFloatingWindow() && dWin->oWin.active);
  2034.     if( frontWindowFlag )
  2035.     {
  2036.         w = er->where;
  2037.  
  2038.         SetPortWindowPort( theWin );
  2039.  
  2040.         GlobalToLocal( &w );
  2041.         if( w.v >= kHeaderHeight && 
  2042.             w.v < kHeaderHeight + ( dWin->linesPerPage*kLineHeight ) )
  2043.         {
  2044.                 if( w.h >= kDataDrawPos &&
  2045.                     w.h < kDataDrawPos + ( kHexWidth * kBytesPerLine ) ) 
  2046.                     MySetCursor( C_IBeam );
  2047.                 else if( w.h >= kTextDrawPos &&
  2048.                          w.h < kTextDrawPos + ( kCharWidth * kBytesPerLine ) )
  2049.                     MySetCursor( C_IBeam );
  2050.                 else
  2051.                     MySetCursor( C_Arrow );
  2052.         }
  2053.         else
  2054.             MySetCursor( C_Arrow );
  2055.  
  2056.         if( dWin->startSel == dWin->endSel ) {
  2057. // LR:            if( ( Ticks & 0x1F ) < 0x10 )
  2058.         if( ( TickCount() & 0x1F ) < 0x10 )
  2059.                 CursorOn( theWin );
  2060.             else
  2061.                 CursorOff( theWin );
  2062.         }
  2063.         // LR: v1.6.5 removed scrap check & grab. Check now in menu update, grab is in paste code
  2064.     }
  2065. }
  2066.  
  2067. // Respond to a mouse-click - highlight cells until the user releases the button
  2068.  
  2069. /*** MY HANDLE CLICK ***/
  2070. void MyHandleClick( WindowRef theWin, Point where, EventRecord *er )
  2071. {
  2072.     Point            w;
  2073.     long            pos, anchorPos = -1,
  2074.                     sPos, ePos;
  2075.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  2076.     SetPortWindowPort( theWin );
  2077.  
  2078.     w = where;
  2079.     GlobalToLocal( &w );
  2080.     if( MyHandleControlClick( theWin, w ) )    // clicked on a window control (ie scrollbar)?
  2081.         return;
  2082.  
  2083.     // No, handle editing chore
  2084.     CursorOff( theWin );
  2085.     if( w.v >= kHeaderHeight && w.v < kHeaderHeight+( dWin->linesPerPage * kLineHeight ) )
  2086.     {
  2087.         do
  2088.         {
  2089.             AutoScroll( dWin, w );
  2090.  
  2091.             if( w.h >= kDataDrawPos && w.h < kTextDrawPos )    //LR 1.72 -- ichy! kDataDrawPos + (kHexWidth * (kBytesPerLine + 1)) )
  2092.             {
  2093.                 pos = (((w.v - kHeaderHeight) / kLineHeight) * kBytesPerLine) + (w.h - kDataDrawPos + (kHexWidth - (kCharWidth*2))) / kHexWidth;
  2094.                 dWin->editMode = EM_Hex;
  2095.             }
  2096.             else if( w.h >= kTextDrawPos && w.h < kTextDrawPos + (kCharWidth * (kBytesPerLine + 1)) )
  2097.             {
  2098.                 pos = (((w.v - kHeaderHeight) / kLineHeight) * kBytesPerLine) + (w.h -  kTextDrawPos + (kCharWidth / 2)) / kCharWidth;
  2099.                 dWin->editMode = EM_Ascii;
  2100.             }
  2101.             else
  2102.                 goto newmousepos;
  2103.  
  2104.             pos += dWin->editOffset;
  2105.             if( pos < dWin->editOffset )
  2106.                 pos = dWin->editOffset;
  2107.             if( pos > dWin->editOffset + (dWin->linesPerPage * kBytesPerLine) )
  2108.                 pos = dWin->editOffset + (dWin->linesPerPage * kBytesPerLine);
  2109.             if( pos > dWin->fileSize )
  2110.                 pos = dWin->fileSize;
  2111.             if( anchorPos == -1 )
  2112.             {
  2113.                 if( er->modifiers & shiftKey )
  2114.                     anchorPos = ( pos < dWin->startSel ) ? dWin->endSel : dWin->startSel;
  2115.                 else anchorPos = pos;
  2116.             }
  2117.             sPos = pos < anchorPos ? pos : anchorPos;
  2118.             ePos = pos > anchorPos ? pos : anchorPos;
  2119.             if( ePos > dWin->fileSize )
  2120.                 ePos = dWin->fileSize;
  2121.  
  2122.             if( sPos != dWin->startSel || ePos != dWin->endSel )
  2123.             {
  2124.                 dWin->startSel = sPos;
  2125.                 dWin->endSel = ePos;
  2126.  
  2127.                 UpdateOnscreen( theWin );
  2128.             }
  2129. newmousepos:
  2130.             GetMouse( &w );
  2131.  
  2132.         } while ( WaitMouseUp() );
  2133.     }
  2134. }
  2135.  
  2136. /*** MY PROCESS KEY ***/
  2137. void MyProcessKey( WindowRef theWin, EventRecord *er )
  2138. {
  2139.     short            charCode, keyCode;
  2140.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  2141.     short            moveOnly = gPrefs.moveOnlyPaging;
  2142.     short            revClearDir = false;
  2143.  
  2144.     keyCode = (er->message & keyCodeMask) >> 8;
  2145.     charCode = (er->message & charCodeMask);
  2146.     if( er->modifiers & cmdKey ) return;
  2147.  
  2148.     if( er->modifiers & optionKey )        //LR 190 -- movement type switches w/option key held down
  2149.         moveOnly = !moveOnly;
  2150.     
  2151.     switch( charCode )    // NS: safer on multi-lingual keyboards
  2152.     {
  2153.         // switch contexts
  2154.         case kTabCharCode:
  2155.         case kReturnCharCode:
  2156.         case kEnterCharCode:
  2157.             if( EM_Hex == dWin->editMode )    //NP 180 -- fix editMode = !editMode as editMode is not a boolean!!!
  2158.                 dWin->editMode = EM_Ascii;
  2159.             else
  2160.                 dWin->editMode = EM_Hex;
  2161.  
  2162.             UpdateOnscreen( dWin->oWin.theWin );
  2163.             break;
  2164.         
  2165.         // move insertion point
  2166.         case kLeftArrowCharCode:
  2167.             _offsetSelection( dWin, -1, (er->modifiers & shiftKey) > 0 );
  2168.             break;
  2169.         case kRightArrowCharCode:
  2170.             _offsetSelection( dWin, 1, (er->modifiers & shiftKey) > 0 );
  2171.             break;
  2172.         case kUpArrowCharCode:
  2173.             if( er->modifiers & optionKey )        //LR 180 -- option up == home
  2174.                 goto dohome;
  2175.  
  2176.             _offsetSelection( dWin, -kBytesPerLine, (er->modifiers & shiftKey) > 0 );
  2177.             break;
  2178.         case kDownArrowCharCode:
  2179.             if( er->modifiers & optionKey )        //LR 180 -- option down == end
  2180.                 goto doend;
  2181.  
  2182.             _offsetSelection( dWin, kBytesPerLine, (er->modifiers & shiftKey) > 0 );
  2183.             break;
  2184.         
  2185.         // scroll document
  2186.         case kPageUpCharCode:
  2187.             if( moveOnly )            //LR 180 -- option to only move display, not selection point
  2188.                 ScrollToPosition( dWin, dWin->editOffset - (kBytesPerLine * (dWin->linesPerPage - 1)) );
  2189.             else
  2190.                 _offsetSelection( dWin, -kBytesPerLine * (dWin->linesPerPage - 1), (er->modifiers & shiftKey) > 0 );
  2191.             break;
  2192.         case kPageDownCharCode:
  2193.             if( moveOnly )            //LR 180 -- option to only move display, not selection point
  2194.                 ScrollToPosition( dWin, dWin->editOffset + (kBytesPerLine * (dWin->linesPerPage - 1)) );
  2195.             else
  2196.                 _offsetSelection( dWin, kBytesPerLine * (dWin->linesPerPage - 1), (er->modifiers & shiftKey) > 0 );
  2197.             break;
  2198.         case kHomeCharCode:
  2199. dohome:
  2200.             _offsetSelection( dWin, 0xFEED, (er->modifiers & shiftKey) > 0 );
  2201.             break;
  2202.         case kEndCharCode:
  2203. doend:
  2204.             _offsetSelection( dWin, 0xBED, (er->modifiers & shiftKey) > 0 );
  2205.             break;
  2206.  
  2207.         //LR 180 -- first, this is useless on read-only files!
  2208.         if( dWin->readOnlyFlag )
  2209.         {
  2210.             ErrorAlert( ES_Stop, errReadOnly );
  2211.             return;
  2212.         }
  2213.  
  2214.         case kClearCharCode:        //LR 180 -- clearing an area is now a seperate command
  2215. clear:
  2216.             if( dWin->endSel == dWin->startSel )    //LR 190 -- if no selection, clear char in front of cursor
  2217.             {
  2218.                 if( dWin->endSel < dWin->fileSize )
  2219.                 {
  2220.                     ObscureCursor();
  2221.                     dWin->endSel++;
  2222.                 }
  2223.             }
  2224. doclear:
  2225.             ClearSelection( dWin );
  2226.             if( revClearDir )
  2227.                 dWin->endSel = dWin->startSel;        //LR 191 -- Move to left or right, as expected
  2228.             else
  2229.                 dWin->startSel = dWin->endSel;
  2230.  
  2231.             ScrollToSelection( dWin, dWin->startSel, false );
  2232.             break;
  2233.  
  2234.         case kDeleteCharCode:    // forward delete
  2235.             if( er->modifiers & optionKey )                //LR 190 -- option key clears
  2236.                 goto clear;
  2237.  
  2238.             if( gPrefs.overwrite && gPrefs.nonDestructive )    //LR 190 -- bad form to use goto, but ...
  2239.                 goto ndbad;
  2240.  
  2241.             if( !dWin->endSel > dWin->startSel )
  2242.                 DeleteSelection( dWin );
  2243.             else if( dWin->startSel > 0L )
  2244.             {
  2245.                 ObscureCursor();
  2246.                 ++dWin->endSel;
  2247.                 DeleteSelection( dWin );
  2248.             }
  2249.             else
  2250. ndbad:
  2251.                 SysBeep(0);
  2252.             break;
  2253.         
  2254.         // delete characters
  2255.         //LR 1.74 -- non-destructive deletes in overwrite mode (paste appr. lenght zero buffer)
  2256.         case kBackspaceCharCode:    // normal delete
  2257.  
  2258.             if( er->modifiers & optionKey )                //LR 180 -- option key clears
  2259.             {
  2260.                 if( dWin->endSel == dWin->startSel )    //LR 190 -- if no selection, clear char behind cursor
  2261.                 {
  2262.                     if( dWin->startSel > 0L )
  2263.                     {
  2264.                         ObscureCursor();
  2265.                         --dWin->startSel;
  2266.                     }
  2267.                 }
  2268.                 revClearDir = true;
  2269.                 goto doclear;
  2270.             }
  2271.  
  2272.             if( gPrefs.overwrite && gPrefs.nonDestructive )    //LR 180 -- non-destructive really is now!
  2273.             {
  2274.                 if( dWin->endSel == dWin->startSel )    // just move selection back one byte
  2275.                 {
  2276.                     if( dWin->startSel > 0L )
  2277.                     {
  2278.                         ObscureCursor();
  2279.                         --dWin->startSel;
  2280.                     }
  2281.                     else
  2282.                         SysBeep(0);
  2283.                 }
  2284.  
  2285.                 dWin->endSel = dWin->startSel;
  2286.                 UpdateOnscreen( dWin->oWin.theWin );
  2287.             }
  2288.             else if( dWin->endSel > dWin->startSel )
  2289.             {
  2290.                 DeleteSelection( dWin );
  2291.             }
  2292.             else if( dWin->startSel > 0L )
  2293.             {
  2294.                 ObscureCursor();
  2295.                 --dWin->startSel;
  2296.                 DeleteSelection( dWin );
  2297.             }
  2298.             else
  2299.                 SysBeep(0);
  2300.             break;
  2301.  
  2302.         // insert/overwrite characters
  2303.         default:
  2304.             // Insert Ascii Text into Area indicated by dWin->startSel - dWin->endSel
  2305.             // Delete Current Selection if > 0
  2306.             ObscureCursor();
  2307.  
  2308.             //LR 190 -- fix overwrite stopping 1 char short and inserting chars past eof
  2309.             if( gPrefs.overwrite && !dWin->loByteFlag && dWin->startSel >= dWin->fileSize )
  2310.             {
  2311.                 SysBeep( 1 );        // overwrite can't insert chars!
  2312.                 break;
  2313.             }
  2314.  
  2315.             // Edit in ASCII frame
  2316.             if( dWin->editMode == EM_Ascii )
  2317.             {
  2318.                 if( (dWin->endSel != dWin->lastTypePos ||
  2319.                     dWin->startSel != dWin->lastTypePos) )
  2320.                     RememberOperation( dWin, EO_Typing, &gUndo );
  2321.                 if( dWin->endSel > dWin->startSel )
  2322.                     RemoveSelection( dWin );
  2323.                 if( gPrefs.overwrite && dWin->startSel < dWin->fileSize )
  2324.                 {
  2325.                     ++dWin->endSel;
  2326.                     RemoveSelection( dWin );
  2327.                 }
  2328.                 InsertCharacter( dWin, charCode );
  2329.                 dWin->lastTypePos = dWin->startSel;
  2330.             }
  2331.             else  // Edit in Hex frame
  2332.             {
  2333.                 short    hexVal;
  2334.  
  2335.                 if( charCode >= '0' && charCode <= '9' )
  2336.                     hexVal = charCode - '0';
  2337.                 else if( charCode >= 'A' && charCode <= 'F' )
  2338.                     hexVal = 0x0A + charCode - 'A';
  2339.                 else if( charCode >= 'a' && charCode <= 'f' )
  2340.                     hexVal = 0x0A + charCode - 'a';
  2341.                 else
  2342.                 {
  2343.                     SysBeep( 1 );
  2344.                     return;
  2345.                 }
  2346.  
  2347.                 if( (dWin->endSel != dWin->lastTypePos ||
  2348.                     dWin->startSel != dWin->lastTypePos) )
  2349.                 {
  2350.                     dWin->loByteFlag = false;
  2351.                     RememberOperation( dWin, EO_Typing, &gUndo );
  2352.                 }
  2353.                 if( dWin->endSel > dWin->startSel )
  2354.                     RemoveSelection( dWin );
  2355.  
  2356.                 if( dWin->loByteFlag )  // Is this the lo-byte of a previous high byte?
  2357.                 {
  2358.                     --dWin->startSel;
  2359.                     RemoveSelection( dWin );
  2360.                     hexVal = hexVal | ( dWin->lastNybble << 4 );
  2361.                     InsertCharacter( dWin, hexVal );
  2362.                     dWin->loByteFlag = false;
  2363.                 }
  2364.                 else
  2365.                 {
  2366.                     if( gPrefs.overwrite )    // we know it's before eof due to previous check
  2367.                     {
  2368.                         ++dWin->endSel;
  2369.                         RemoveSelection( dWin );    // for overwrite, we delete current char and then insert new one ;)
  2370.                     }
  2371.                     InsertCharacter( dWin, hexVal );
  2372.                     dWin->lastNybble = hexVal;
  2373.                     dWin->loByteFlag = true;
  2374.                 }
  2375.                 dWin->lastTypePos = dWin->startSel;
  2376.             }
  2377.             break;
  2378.     }
  2379. }
  2380.  
  2381. /*** CURSOR OFF ***/
  2382. void CursorOff( WindowRef theWin )
  2383. {
  2384.     if( g.cursorFlag )
  2385.     {
  2386.         g.cursorFlag = false;
  2387.         SetPortWindowPort( theWin );
  2388.         InvertRect( &g.cursRect );
  2389.     }
  2390. }
  2391.  
  2392. /*** CURSOR ON ***/
  2393. void CursorOn( WindowRef theWin )
  2394. {
  2395.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  2396.     long            start;
  2397.  
  2398.     if( !g.cursorFlag && dWin->startSel >= dWin->editOffset && dWin->startSel < dWin->editOffset + ( dWin->linesPerPage * kBytesPerLine ) ) 
  2399.     {
  2400.         g.cursorFlag = true;
  2401.         SetPortWindowPort( theWin );
  2402.  
  2403.         start = dWin->startSel - dWin->editOffset;
  2404.  
  2405.         if( dWin->editMode == EM_Hex )
  2406.         {
  2407.             g.cursRect.top = kHeaderHeight + LINENUM(start) * kLineHeight;
  2408.             g.cursRect.bottom = g.cursRect.top + kLineHeight;
  2409.             g.cursRect.left = kDataDrawPos /*kBodyDrawPos + CHARPOS(kStringHexPos - 1)*/ + (COLUMN(start) * kHexWidth) - 2;
  2410.             g.cursRect.right = g.cursRect.left + 2;
  2411.  
  2412.             InvertRect( &g.cursRect );
  2413.         }
  2414.         else
  2415.         {
  2416.             g.cursRect.top = kHeaderHeight + LINENUM(start) * kLineHeight;
  2417.             g.cursRect.bottom = g.cursRect.top + kLineHeight;
  2418.             g.cursRect.left = kTextDrawPos /*kBodyDrawPos + CHARPOS(kStringTextPos)*/ + (COLUMN(start) * kCharWidth) - 1;
  2419.             g.cursRect.right = g.cursRect.left + 2;
  2420.  
  2421.             InvertRect( &g.cursRect );
  2422.         }
  2423.     }
  2424. }
  2425.  
  2426. #pragma mark -
  2427.  
  2428. #if TARGET_API_MAC_CARBON
  2429.  
  2430. // SEL: 1.7 - added carbon printing (function rearrangment by LR)
  2431.  
  2432. /*------------------------------------------------------------------------------
  2433.     Get the printing information from the end user
  2434.  
  2435.     Parameters:
  2436.         printSession    -   current printing session
  2437.         pageFormat      -   a PageFormat object addr
  2438.         printSettings   -   a PrintSettings object addr
  2439.  
  2440.     Description:
  2441.         If the caller passes an empty PrintSettings object, create a new one,
  2442.         otherwise validate the one provided by the caller.
  2443.         Invokes the Print dialog and checks for Cancel.
  2444.         Note that the PrintSettings object is modified by this function.
  2445.  
  2446. ------------------------------------------------------------------------------*/
  2447. static OSStatus _doPrintDialog( PMPrintSession printSession, PMPageFormat pageFormat, PMPrintSettings* printSettings )
  2448. {
  2449.     OSStatus    status;
  2450.     Boolean     accepted;
  2451.     UInt32      minPage = 1,
  2452.                 maxPage = 9999;
  2453.  
  2454.     //  In this sample code the caller provides a valid PageFormat reference but in
  2455.     //  your application you may want to load and unflatten the PageFormat object
  2456.     //  that was saved at PageSetup time.  See LoadAndUnflattenPageFormat below.
  2457.  
  2458.     //  Set up a valid PrintSettings object.
  2459.     if (*printSettings == kPMNoPrintSettings)
  2460.     {
  2461.         status = PMCreatePrintSettings(printSettings);
  2462.  
  2463.         //  Note that PMPrintSettings is not session-specific, but calling
  2464.         //  PMSessionDefaultPrintSettings assigns values specific to the printer
  2465.         //  associated with the current printing session.
  2466.         if ((status == noErr) && (*printSettings != kPMNoPrintSettings))
  2467.             status = PMSessionDefaultPrintSettings(printSession, *printSettings);
  2468.     }
  2469.     else
  2470.         status = PMSessionValidatePrintSettings(printSession, *printSettings,
  2471.                     kPMDontWantBoolean);
  2472.     //  Set a valid page range before displaying the Print dialog
  2473.     if (status == noErr)
  2474.         status = PMSetPageRange(*printSettings, minPage, maxPage);
  2475.  
  2476.     //  Display the Print dialog.
  2477.     if (status == noErr)
  2478.     {
  2479.         status = PMSessionPrintDialog(printSession, *printSettings, pageFormat,
  2480.                     &accepted);
  2481.         if (!accepted)
  2482.             status = kPMCancel; // user clicked Cancel button
  2483.     }
  2484.  
  2485.     return( status );
  2486. }
  2487.  
  2488. /*------------------------------------------------------------------------------
  2489.     Print the pages
  2490.  
  2491.     Parameters:
  2492.         printSession    -   current printing session
  2493.         pageFormat      -   a PageFormat object addr
  2494.         printSettings   -   a PrintSettings object addr
  2495.  
  2496.     Description:
  2497.         Assumes the caller provides validated PageFormat and PrintSettings objects.
  2498.         Calculates a valid page range and prints each page by calling _drawDump.
  2499.  
  2500. ------------------------------------------------------------------------------*/
  2501. static void _doPrintLoop( PMPrintSession printSession, PMPageFormat pageFormat, PMPrintSettings printSettings, EditWindowPtr dWin )
  2502. {
  2503.     OSStatus status,
  2504.              printError;
  2505.     PMRect    pageRect;
  2506.     SInt32    startAddr, endAddr, linesPerPage, addr;
  2507.     UInt32    realNumberOfPagesinDoc,
  2508.              pageNumber,
  2509.              firstPage,
  2510.              lastPage;
  2511.  
  2512.     //  PMGetAdjustedPaperRect returns the paper size taking into account rotation,
  2513.     //  resolution, and scaling settings.  Note this is the paper size selected
  2514.     //  the Page Setup dialog.  It is not guaranteed to be the same as the paper
  2515.     //  size selected in the Print dialog on Mac OS X.
  2516.     status = PMGetAdjustedPaperRect(pageFormat, &pageRect);
  2517.  
  2518.     //  PMGetAdjustedPageRect returns the page size taking into account rotation,
  2519.     //  resolution, and scaling settings.  Note this is the imageable area of the
  2520.     //  paper selected in the Page Setup dialog.
  2521.     //  DetermineNumberOfPagesInDoc returns the number of pages required to print
  2522.     //  the document.
  2523.     if (status == noErr)
  2524.     {
  2525.       status = PMGetAdjustedPageRect(pageFormat, &pageRect);
  2526.       if (status == noErr)
  2527.       {
  2528.             if( dWin->startSel == dWin->endSel )
  2529.             {
  2530.                 startAddr = 0;
  2531.                 endAddr = dWin->fileSize;
  2532.             }
  2533.             else
  2534.             {
  2535.                 startAddr = dWin->startSel;
  2536.                 endAddr = dWin->endSel;
  2537.             }
  2538.  
  2539.             addr = startAddr;
  2540. //LR: 1.7 -fix lpp calculation!            linesPerPage = (pageRect.bottom - TopMargin - (kHeaderHeight + 1)) / kLineHeight;
  2541.             linesPerPage = ((pageRect.bottom - pageRect.top) + (kLineHeight / 3) - (kHeaderHeight + kFooterHeight)) / kLineHeight;
  2542.             realNumberOfPagesinDoc = (((endAddr - startAddr) / kBytesPerLine) / linesPerPage) + 1;
  2543.         }
  2544.     }
  2545.  
  2546.     //  Get the user's selection for first and last pages
  2547.     if (status == noErr)
  2548.     {
  2549.       status = PMGetFirstPage(printSettings, &firstPage);
  2550.       if (status == noErr)
  2551.           status = PMGetLastPage(printSettings, &lastPage);
  2552.     }
  2553.  
  2554.     //  Check that the selected page range does not go beyond the actual
  2555.     //  number of pages in the document.
  2556.     if (status == noErr)
  2557.     {
  2558.         if( firstPage > realNumberOfPagesinDoc )
  2559.         {
  2560.             status = kPMValueOutOfRange;
  2561.             PMSessionSetError (printSession, kPMValueOutOfRange);
  2562.         }
  2563.  
  2564.         if (realNumberOfPagesinDoc < lastPage)
  2565.             lastPage = realNumberOfPagesinDoc;
  2566.     }
  2567.  
  2568.     //  NOTE:  We don't have to worry about the number of copies.  The Printing
  2569.     //  Manager handles this.  So we just iterate through the document from the
  2570.     //  first page to be printed, to the last.
  2571.     if (status == noErr)
  2572.     { //  Establish a graphics context for drawing the document's pages.
  2573.       //  Although it's not used in this sample code, PMGetGrafPtr can be called
  2574.       //  get the QD grafport.
  2575.       status = PMSessionBeginDocument(printSession, printSettings, pageFormat);
  2576.       if (status == noErr)
  2577.       { //  Print all the pages in the document.  Note that we spool all pages
  2578.             //  and rely upon the Printing Manager to print the correct page range.
  2579.             //  In this sample code we assume the total number of pages in the
  2580.             //  document is equal to "lastPage".
  2581.             pageNumber = 1;
  2582.             while ((pageNumber <= lastPage) && (PMSessionError(printSession) == noErr))
  2583.             {
  2584.                 Rect    r;
  2585.                 
  2586.                 //  NOTE:  We don't have to deal with the old Printing Manager's
  2587.                 //  128-page boundary limit anymore.
  2588.  
  2589.                 //  Set up a page for printing.
  2590.                 status = PMSessionBeginPage(printSession, pageFormat, &pageRect);
  2591.                 if (status != noErr)
  2592.                   break;
  2593.  
  2594.                 //  Draw the page.
  2595.                 r.top = (short)(pageRect.top);
  2596.                 r.left = (short)(pageRect.left);
  2597.                 r.bottom = r.top + kHeaderHeight - 1;
  2598.                 r.right = (short)(pageRect.right);
  2599.                 _drawHeader( dWin, &r );
  2600.  
  2601.                 r.top += kHeaderHeight;
  2602.                 r.bottom = pageRect.bottom - kFooterHeight;
  2603.                 _drawDump( dWin, &r, addr, endAddr );
  2604.  
  2605.                 r.top = r.bottom;
  2606.                 r.bottom += kFooterHeight;
  2607.                 _drawFooter( dWin, &r, pageNumber, realNumberOfPagesinDoc );
  2608.  
  2609.                 //  Close the page.
  2610.                 status = PMSessionEndPage(printSession);
  2611.                 if (status != noErr)
  2612.                   break;
  2613.  
  2614.                 addr += linesPerPage * kBytesPerLine;
  2615.                 addr -= ( addr % kBytesPerLine );
  2616.  
  2617.                 //  And loop.
  2618.                 pageNumber++;
  2619.             }
  2620.  
  2621.             // Close the printing port
  2622.             (void)PMSessionEndDocument(printSession);
  2623.       }
  2624.     }
  2625.  
  2626.     //  Only report a printing error once we have completed the print loop. This
  2627.     //  ensures that every PMSessionBegin... call is followed by a matching
  2628.     //  PMSessionEnd... call, so the Printing Manager can release all temporary
  2629.     //  memory and close properly.
  2630.     printError = PMSessionError(printSession);
  2631.     if ( ( kPMCancel != printError) && (printError != noErr) )
  2632.       PostPrintingErrors(printError);
  2633. }
  2634.  
  2635. // NS: v1.6.6, event filters for navigation services
  2636.  
  2637. #endif    //TARGET_API_MAC_CARBON  -- BB: moved _navEventFilter from Carbon only
  2638.  
  2639. /*** PRINT WINDOW ***/
  2640. void PrintWindow( EditWindowPtr dWin )
  2641. {
  2642. #if TARGET_API_MAC_CARBON    // SEL: 1.7 - carbon printing
  2643.     // Carbon session based printing variables 
  2644.     OSStatus            status;
  2645.     PMPrintSession    printSession;
  2646.     PMPrintSettings    printSettings;
  2647.     PMPageFormat        pageFormat;
  2648. #else
  2649.     Boolean            ok;
  2650.     Rect            pageRect, r;
  2651.     TPPrPort        printPort;
  2652.     TPrStatus        prStatus;
  2653.     short        pageNbr, startPage, endPage, nbrPages;
  2654.     long        startAddr, endAddr, addr;
  2655.     short        linesPerPage;
  2656. #endif
  2657.  
  2658.     GrafPtr        savePort;
  2659.  
  2660.     GetPort( &savePort );
  2661.  
  2662. #if TARGET_API_MAC_CARBON    // SEL: 1.7 - implemented Carbon printing
  2663.  
  2664.     // make a new printing session
  2665.     status = PMCreateSession(&printSession);
  2666.     if ( noErr != status )
  2667.     {
  2668.         PostPrintingErrors(status);
  2669.         return;
  2670.     }
  2671.     if ( kPMNoPageFormat == g.pageFormat )
  2672.     {
  2673.         status = PMCreatePageFormat(&pageFormat);
  2674.         //  Note that PMPageFormat is not session-specific, but calling
  2675.         //  PMSessionDefaultPageFormat assigns values specific to the printer
  2676.         //  associated with the current printing session.
  2677.         if ((status == noErr) && (pageFormat != kPMNoPageFormat))
  2678.         {
  2679.             status = PMSessionDefaultPageFormat(printSession, pageFormat);
  2680.         }
  2681.     }
  2682.     else
  2683.     { // already have a pageFormat, prolly because the user selected Page Setup
  2684.         status = PMCreatePageFormat(&pageFormat);
  2685.         status = PMCopyPageFormat(g.pageFormat, pageFormat);
  2686.         if ( noErr == status )
  2687.         {
  2688.             status = PMSessionValidatePageFormat(printSession, pageFormat, kPMDontWantBoolean);
  2689.         }
  2690.     }
  2691.     if ( noErr != status )
  2692.     {
  2693.         PostPrintingErrors(status);
  2694.         (void)PMRelease(printSession);
  2695.         return;
  2696.     }
  2697.     if ( kPMNoPrintSettings != g.printSettings )
  2698.     {
  2699.         status = PMCreatePrintSettings(&printSettings);
  2700.         status = PMCopyPrintSettings(g.printSettings, printSettings);
  2701.     }
  2702.     else
  2703.     {
  2704.         printSettings = kPMNoPrintSettings;
  2705.     }
  2706.     if ( noErr != status )
  2707.     {
  2708.         PostPrintingErrors(status);
  2709.         (void)PMRelease(pageFormat);
  2710.         (void)PMRelease(printSession);
  2711.         return;
  2712.     }
  2713.   //  Display the Print dialog.
  2714.     status = _doPrintDialog(printSession, pageFormat, &printSettings);
  2715.     if  ( kPMCancel != status )
  2716.     { // user did not cancel the print dialog box
  2717.         if ( ( noErr == status ) )
  2718.         { //  Execute the print loop.
  2719.             _doPrintLoop(printSession, pageFormat, printSettings, dWin);
  2720.         }
  2721.         else
  2722.         {
  2723.             PostPrintingErrors(status);
  2724.             return;
  2725.         }
  2726.     }
  2727.  
  2728.     //  Release the PageFormat and PrintSettings objects.  PMRelease decrements the
  2729.     //  ref count of the allocated objects.  We let the Printing Manager decide when
  2730.     //  to release the allocated memory.
  2731.     if (pageFormat != kPMNoPageFormat)
  2732.     {
  2733.         (void)PMRelease(pageFormat);
  2734.     }
  2735.     if (printSettings != kPMNoPrintSettings)
  2736.     {
  2737.         (void)PMRelease(printSettings);
  2738.     }
  2739.     //  Terminate the current printing session.
  2740.     (void)PMRelease(printSession);
  2741.  
  2742. #else    // non-Carbon printing
  2743.  
  2744.     PrOpen();
  2745.  
  2746.     PrValidate( g.HPrint );
  2747.     ok = PrJobDialog( g.HPrint );
  2748.     if( ok )
  2749.     {
  2750.         if( dWin->startSel == dWin->endSel )
  2751.         {
  2752.             startAddr = 0;
  2753.             endAddr = dWin->fileSize;
  2754.         }
  2755.         else
  2756.         {
  2757.             startAddr = dWin->startSel;
  2758.             endAddr = dWin->endSel;
  2759.         }
  2760.  
  2761.         printPort = PrOpenDoc( g.HPrint, NULL, NULL );
  2762.  
  2763.         //LR 188 -- from Ron Langley; the below is the screen rectangle, not the page rectangle!
  2764.         //r = printPort->gPort.portRect;
  2765.         r = pageRect = (*g.HPrint)->prInfo.rPage;    // the printed page rectangle
  2766.  
  2767. //LR: 1.7 -fix lpp calculation!        linesPerPage = ( r.bottom - TopMargin - ( kHeaderHeight + 1 ) ) / kLineHeight;
  2768.             linesPerPage = ((r.bottom - r.top) + (kLineHeight / 3) - (kHeaderHeight + kFooterHeight)) / kLineHeight;
  2769.         nbrPages = ((endAddr - startAddr) / kBytesPerLine) / linesPerPage + 1;
  2770.  
  2771.         startPage = ( **g.HPrint ).prJob.iFstPage;
  2772.         endPage = ( **g.HPrint ).prJob.iLstPage;
  2773.         if( startPage > nbrPages )
  2774.         {
  2775.             PrCloseDoc( printPort );
  2776.             ErrorAlert( ES_Caution, errPrintRange, nbrPages );
  2777.             goto ErrorExit;
  2778.         }
  2779.         addr = startAddr;
  2780.  
  2781.         if( endPage > nbrPages )
  2782.             endPage = nbrPages;
  2783.  
  2784.         ctHdl = NULL;    // print in black & white!
  2785.  
  2786.         for ( pageNbr = 1; pageNbr <= nbrPages; ++pageNbr )
  2787.         {
  2788.             SetPort( &printPort->gPort );
  2789.             PrOpenPage( printPort, NULL );
  2790.     
  2791.             if( pageNbr >= startPage && pageNbr <= endPage )
  2792.             {
  2793.                 r = pageRect;
  2794.                 r.bottom = r.top + kHeaderHeight - 1;        //LR: 1.7 - don't erase entire page!
  2795.                 _drawHeader( dWin, &r );
  2796.         
  2797.                 r.top += kHeaderHeight;
  2798.                 r.bottom = pageRect.bottom - kFooterHeight;
  2799.                 _drawDump( dWin, &r, addr, endAddr );
  2800.     
  2801.                 r.top = r.bottom;
  2802.                 r.bottom += kFooterHeight;
  2803.                 _drawFooter( dWin, &r, pageNbr, nbrPages );    //SEL: 1.7 - fix Lane's DrawDump usage (what was I thinking? P)
  2804.             }
  2805.  
  2806.             addr += linesPerPage * kBytesPerLine;
  2807.             addr -= ( addr % kBytesPerLine );
  2808.             PrClosePage( printPort );
  2809.         }
  2810.         PrCloseDoc( printPort );
  2811.         if( ( **g.HPrint ).prJob.bJDocLoop == bSpoolLoop && PrError() == noErr )
  2812.             PrPicFile( g.HPrint, NULL, NULL, NULL, &prStatus );
  2813.     }
  2814. ErrorExit:
  2815.     PrClose();
  2816. #endif
  2817.     SetPort( savePort );
  2818. }
  2819.  
  2820. #pragma mark -
  2821.  
  2822. /*** COPY FORK ***/
  2823. static OSStatus _copyFork( FSSpec *srcSpec, FSSpec *dstSpec, short forkType )
  2824. {
  2825.     OSStatus error;
  2826.     short    sRefNum, dRefNum;
  2827.     Ptr        tBuffer;
  2828.     long    srcSize=0L, bufSize, count;
  2829.  
  2830.     tBuffer = NewPtr( 32000 );
  2831.  
  2832.     if( !tBuffer )
  2833.     {
  2834.         ErrorAlert( ES_Caution, errMemory );
  2835.         return 1;
  2836.     }
  2837.     if( forkType == FT_Resource )
  2838.     {
  2839. //LR 175        error = HOpenRF( srcSpec->vRefNum, srcSpec->parID, srcSpec->name, fsRdPerm, &sRefNum );
  2840.         error = FSpOpenRF( srcSpec, fsRdPerm, &sRefNum );
  2841.         if( error != noErr )
  2842.         {
  2843.             ErrorAlert( ES_Caution, errSave, error );
  2844.             return error;
  2845.         }
  2846. //LR 175        error = HOpenRF( dstSpec->vRefNum, dstSpec->parID, dstSpec->name, fsWrPerm, &dRefNum );
  2847.         error = FSpOpenRF( dstSpec, fsWrPerm, &dRefNum );
  2848.         if( error != noErr )
  2849.         {
  2850.             ErrorAlert( ES_Caution, errSave, error );
  2851.             return error;
  2852.         }
  2853.     }
  2854.     else
  2855.     {
  2856. //LR 175        error = HOpen( srcSpec->vRefNum, srcSpec->parID, srcSpec->name, fsRdPerm, &sRefNum );
  2857.         error = FSpOpenDF( srcSpec, fsRdPerm, &sRefNum );
  2858.         if( error != noErr )
  2859.         {
  2860.             ErrorAlert( ES_Caution, errSave, error );
  2861.             return error;
  2862.         }
  2863. //LR 175        error = HOpen( dstSpec->vRefNum, dstSpec->parID, dstSpec->name, fsWrPerm, &dRefNum );
  2864.         error = FSpOpenDF( dstSpec, fsWrPerm, &dRefNum );
  2865.         if( error != noErr )
  2866.         {
  2867.             ErrorAlert( ES_Caution, errSave, error );
  2868.             return error;
  2869.         }
  2870.     }
  2871.     GetEOF( sRefNum, &srcSize );
  2872.     SetEOF( dRefNum, 0L );
  2873.     while( srcSize )
  2874.     {
  2875.         if( srcSize < 32000 )
  2876.             bufSize = srcSize;
  2877.         else
  2878.             bufSize = 32000;
  2879.         srcSize -= bufSize;
  2880.         count = bufSize;
  2881.         error = FSRead( sRefNum, &count, tBuffer );
  2882.         if( error != noErr )
  2883.         {
  2884.             ErrorAlert( ES_Caution, errRead, error );
  2885.             goto ErrorExit;
  2886.         }
  2887.         error = FSWrite( dRefNum, &count, tBuffer );
  2888.         if( error != noErr )
  2889.         {
  2890.             ErrorAlert( ES_Caution, errWrite, error );
  2891.             goto ErrorExit;
  2892.         }
  2893.     }
  2894.     error = noErr;
  2895. ErrorExit:
  2896.     FSClose( sRefNum );
  2897.     FSClose( dRefNum );
  2898.     DisposePtr( tBuffer );
  2899.     return error;
  2900. }
  2901.  
  2902. /*** SAVE CONTENTS ***/
  2903. void SaveContents( WindowRef theWin )
  2904. {
  2905.     short            tRefNum = 0;
  2906.     FSSpec            tSpec, bSpec;
  2907.     HParamBlockRec    pb;
  2908.     EditChunk        **cc;
  2909.     long            count;
  2910.     OSStatus        error;
  2911.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  2912.  
  2913.     //LR 180 -- first, this is useless on read-only files!
  2914.     if( dWin->readOnlyFlag )
  2915.     {
  2916.         ErrorAlert( ES_Stop, errReadOnly );
  2917.         return;
  2918.     }
  2919.  
  2920.     // if we don't have a file spec it's a new window, do a Save As...
  2921.     if( dWin->destSpec.name[0] == 0 )
  2922.     {
  2923.         SaveAsContents( theWin );
  2924.         return;
  2925.     }
  2926.  
  2927.     // OK, ready to save ... first create our temp work file
  2928.     tSpec = dWin->destSpec;
  2929.  
  2930.     // If original file exists, write to temp file
  2931.     if( dWin->refNum )
  2932.     {
  2933.         if( tSpec.name[0] < 31 )
  2934.         {
  2935.             tSpec.name[0]++;
  2936.             tSpec.name[tSpec.name[0]] = '^';    //LR 1.72 -- temp files end with ^
  2937.         }
  2938.         else    tSpec.name[31] ^= 0x10;
  2939.     }
  2940. //LR 1.73 -- delete temp files!        _ensureNameIsUnique( &tSpec );
  2941.  
  2942. //LR 175        HDelete( tSpec.vRefNum, tSpec.parID, tSpec.name );
  2943.     FSpDelete( &tSpec );
  2944. //LR 175        error = HCreate( tSpec.vRefNum, tSpec.parID, tSpec.name, dWin->creator, dWin->fileType );
  2945.     error = FSpCreate( &tSpec, dWin->creator, dWin->fileType, smSystemScript );
  2946.     if( error != noErr )
  2947.     {
  2948.         ErrorAlert( ES_Caution, errCreate, error );
  2949.         return;
  2950.     }
  2951.  
  2952.     // Preserve creation date of orig file if it exists
  2953.     if( dWin->creationDate )
  2954.     {
  2955.         pb.fileParam.ioCompletion = 0l;
  2956.         pb.fileParam.ioNamePtr = tSpec.name;
  2957.         pb.fileParam.ioVRefNum = tSpec.vRefNum;
  2958.         pb.fileParam.ioDirID = tSpec.parID;
  2959.         pb.fileParam.ioFDirIndex = 0;
  2960.     
  2961.         if( ( error = PBHGetFInfo( &pb, false ) ) != noErr )
  2962.         {
  2963.             ErrorAlert( ES_Caution, errFileInfo, error );
  2964.             return;
  2965.         }
  2966.         // Reset dirID which PBHGeFInfo changes...
  2967.         pb.fileParam.ioFlCrDat = dWin->creationDate;
  2968.         pb.fileParam.ioDirID = tSpec.parID;
  2969.         if( ( error = PBHSetFInfo( &pb, false ) ) != noErr )
  2970.         {
  2971.             ErrorAlert( ES_Caution, errSetFileInfo, error );
  2972.             return;
  2973.         }
  2974.     }
  2975.     // Preserve other fork if it exists (LR 1.73 can't do !fork because fork #s are now 1 & 2!)
  2976.     if( dWin->refNum )
  2977.         if( _copyFork( &dWin->fsSpec, &tSpec, (dWin->fork == FT_Data) ? FT_Resource : FT_Data ) != noErr )
  2978.             return;
  2979.  
  2980.     // Open the temp file
  2981.     if( dWin->fork == FT_Resource )
  2982.     {
  2983. //LR 175            error = HOpenRF( tSpec.vRefNum, tSpec.parID, tSpec.name, fsWrPerm, &tRefNum );
  2984.         error = FSpOpenRF( &tSpec, fsWrPerm, &tRefNum );
  2985.         if( error != noErr )
  2986.         {
  2987.             ErrorAlert( ES_Caution, errSave, error );
  2988.             return;
  2989.         }
  2990.     }
  2991.     else
  2992.     {
  2993. //LR 175            error = HOpenDF( tSpec.vRefNum, tSpec.parID, tSpec.name, fsWrPerm, &tRefNum );
  2994.         FSpOpenDF( &tSpec, fsWrPerm, &tRefNum );
  2995.         if( error != noErr )
  2996.         {
  2997.             ErrorAlert( ES_Caution, errSave, error );
  2998.             return;
  2999.         }
  3000.     }
  3001.     
  3002.     // Save out to temp file
  3003.     cc = dWin->firstChunk;
  3004.     while( cc )
  3005.     {
  3006.         LoadChunk( dWin, cc );
  3007.         count = ( *cc ) ->size;
  3008.         error = FSWrite( tRefNum, &count, *( *cc ) ->data );
  3009.         if( error != noErr )
  3010.         {
  3011.             // !! Error Message - write error
  3012.             FSClose( tRefNum );
  3013.             if( error == dskFulErr )
  3014.             {
  3015.                 ErrorAlert( ES_Stop, errDiskFull );
  3016.                 FSpDelete( &tSpec );
  3017. //LR 175                    HDelete( tSpec.vRefNum, tSpec.parID, tSpec.name );
  3018.             }
  3019.             else
  3020.                 ErrorAlert( ES_Caution, errWrite, error );
  3021.  
  3022.             return;
  3023.         }
  3024.         cc = ( *cc ) ->next;
  3025.     }
  3026.  
  3027.     // Close temp file
  3028.     FSClose( tRefNum );
  3029.  
  3030.     // If Original File Exists
  3031.     if( dWin->refNum )
  3032.     {
  3033.         // Close original file
  3034.         FSClose( dWin->refNum );
  3035.  
  3036.         bSpec = dWin->destSpec;
  3037.  
  3038.         // If it exists under current name
  3039. //LR 175            if( ( error = HOpen( bSpec.vRefNum, bSpec.parID, bSpec.name, fsRdPerm, &dWin->refNum ) ) == noErr )
  3040.         if( ( error = FSpOpenDF( &bSpec, fsRdPerm, &dWin->refNum ) ) == noErr )
  3041.         {
  3042.             FSClose( dWin->refNum );
  3043.  
  3044.             if( gPrefs.backupFlag )
  3045.             {
  3046.                 // Delete last backup file, if it exists
  3047.                 bSpec = dWin->destSpec;
  3048.                 if( bSpec.name[0] < 31 )    // LR: 000505 -- don't go beyond 31 chars!
  3049.                     bSpec.name[0]++;
  3050.                 bSpec.name[bSpec.name[0]] = '~';
  3051.                 FSpDelete( &bSpec );
  3052. //LR 175                    HDelete( bSpec.vRefNum, bSpec.parID, bSpec.name );    // backup files end with ~
  3053.     
  3054.                 // Rename original file to backup name
  3055. //LR 175                    error = HRename( dWin->destSpec.vRefNum, dWin->destSpec.parID, dWin->destSpec.name, bSpec.name );
  3056.                 FSpRename( &dWin->destSpec, bSpec.name );
  3057.                 if( error != noErr )
  3058.                 {
  3059.                     // Backup is probably open, just delete original
  3060.                     ErrorAlert( ES_Caution, errBackup, error );
  3061. //LR 175                        bSpec = dWin->destSpec;
  3062.                     FSpDelete( &dWin->destSpec );
  3063. //LR 175                        HDelete( bSpec.vRefNum, bSpec.parID, bSpec.name );
  3064.                 }
  3065.             }
  3066.             else
  3067.             {
  3068.                 // Delete Original if backup flag is false
  3069. //LR 175                    bSpec = dWin->destSpec;
  3070.                 FSpDelete( &dWin->destSpec );
  3071. //LR 175                    HDelete( bSpec.vRefNum, bSpec.parID, bSpec.name );
  3072.             }
  3073.         }
  3074.  
  3075.         /* now, for OS X, we need to get the catalog information for later restoration when saving (file permissions) */
  3076.  
  3077. #if !defined(__MC68K__) && !defined(__SC__)
  3078.         if( FSSetCatalogInfo && dWin->OKToSetCatInfo )    /* not available in all systems (OS 9 and later only it seems) */
  3079.         {
  3080.             FSRef ref;
  3081.  
  3082.             error = FSpMakeFSRef( &tSpec, &ref );
  3083.             if( !error )
  3084.             {
  3085.                 error = FSSetCatalogInfo( &ref, kFSCatInfoSettableInfo, &dWin->catinfo );
  3086.             }
  3087.         }
  3088. #endif
  3089.         // Rename temp file to correct name
  3090. //LR 175            error = HRename( tSpec.vRefNum, tSpec.parID, tSpec.name, dWin->destSpec.name );
  3091.         error = FSpRename( &tSpec, dWin->destSpec.name );
  3092.         if( error != noErr )
  3093.             ErrorAlert( ES_Stop, errRename, error );
  3094.     }
  3095.  
  3096.     // Open newly saved file read only
  3097.     tSpec = dWin->destSpec;
  3098.     if( dWin->fork == FT_Resource )
  3099.     {
  3100. //LR 175            error = HOpenRF( tSpec.vRefNum, tSpec.parID, tSpec.name, fsRdPerm, &dWin->refNum );
  3101.         error = FSpOpenRF( &tSpec, fsRdWrPerm, &dWin->refNum );
  3102.         if( error != noErr )
  3103.             ErrorAlert( ES_Stop, errSave, error );
  3104.     }
  3105.     else
  3106.     {
  3107. //LR 175            error = HOpenDF( tSpec.vRefNum, tSpec.parID, tSpec.name, fsRdPerm, &dWin->refNum );
  3108.         error = FSpOpenDF( &tSpec, fsRdWrPerm, &dWin->refNum );
  3109.         if( error != noErr )
  3110.             ErrorAlert( ES_Stop, errSave, error );
  3111.     }
  3112.  
  3113.     // Reset Work File
  3114.     dWin->fsSpec = dWin->destSpec;
  3115. //LR: 1.7        SetWTitle( dWin->oWin.theWin, dWin->fsSpec.name );
  3116.  
  3117.     dWin->workBytesWritten = 0L;
  3118.     SetEOF( dWin->workRefNum, 0L );
  3119.  
  3120.     // Flush the volume
  3121.     pb.volumeParam.ioCompletion = NULL;
  3122.     pb.volumeParam.ioNamePtr = NULL;
  3123.     pb.volumeParam.ioVRefNum = tSpec.vRefNum;
  3124.     PBFlushVolSync( ( ParmBlkPtr ) &pb );
  3125.  
  3126.     // Clear linked list
  3127.     UnloadFile( dWin );
  3128.  
  3129.     // Rebuilt linked list
  3130.     LoadFile( dWin );
  3131.  
  3132.     // Clear Dirty Flag
  3133.     dWin->dirtyFlag = false;
  3134.  
  3135.     return;
  3136. }
  3137.  
  3138. /*** SAVE AS CONTENTS ***/
  3139. void SaveAsContents( WindowRef theWin )
  3140. {
  3141.     short id;
  3142.     Str255 title;
  3143.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  3144.  
  3145.     // LR: 1.7 - must remove item so that if name changes we can add it back w/new name :)
  3146.     GetWTitle( theWin, title );
  3147.     id = GetWindowMenuItemID( title );
  3148.     if( id )
  3149.         DeleteMenuItem( GetMenuHandle(kWindowMenu), id );
  3150.  
  3151. #if !defined(__MC68K__) && !defined(__SC__)        //LR 1.73 -- not available for 68K (won't even link!)
  3152.     if( g.useNavServices ) // BB: replaced #if TARGET_API_MAC_CARBON    // LR: v1.6
  3153.     {
  3154.         OSStatus error = noErr;
  3155.         NavReplyRecord        reply;
  3156.         NavDialogOptions    dialogOptions;
  3157.         NavEventUPP            eventProc = NewNavEventUPP( _navEventFilter );
  3158.  
  3159.         NavGetDefaultDialogOptions( &dialogOptions );
  3160. //LR: 1.7 not w/modified window titles!    GetWTitle( theWin, dialogOptions.savedFileName );
  3161.         // 05/10/01 - GAB: copy the ENTIRE name, including the last character (hence, the "+ 1" on the count parameter)
  3162.         BlockMoveData( dWin->fsSpec.name, dialogOptions.savedFileName, dWin->fsSpec.name[0] + 1 );
  3163.         GetIndString( dialogOptions.message, strPrompt, 1 );    //LR 180 -- modify prompt
  3164.  
  3165.         error = NavPutFile( NULL, &reply, &dialogOptions, eventProc, kDefaultFileType, kAppCreator, NULL );
  3166.         if( reply.validRecord || !error )
  3167.         {
  3168.             AEKeyword     keyword;
  3169.             DescType     descType;
  3170.             FSSpec        savedSpec;    
  3171.             Size         actualSize;
  3172.             
  3173.             error = AEGetNthPtr( &(reply.selection), 1, typeFSS, &keyword, &descType, &savedSpec, sizeof(FSSpec), &actualSize );
  3174.             if( !error )
  3175.             {
  3176.                 dWin->destSpec = savedSpec;
  3177.                 dWin->creationDate = 0;
  3178.                 dWin->readOnlyFlag = false;
  3179.                 SaveContents( theWin );
  3180.                 NavCompleteSave( &reply, kNavTranslateInPlace );
  3181.             }
  3182.             NavDisposeReply( &reply );
  3183.         }
  3184.         DisposeNavEventUPP( eventProc );
  3185.     }
  3186. #if !TARGET_API_MAC_CARBON
  3187.     else // BB: only used if not in carbon
  3188. #endif
  3189. #endif    //POWERPC
  3190. #if !TARGET_API_MAC_CARBON
  3191.     {
  3192.         StandardFileReply    reply;
  3193.         EditWindowPtr        dWin = (EditWindowPtr) GetWRefCon( theWin );
  3194.         Str63                /*fileName,*/ prompt;
  3195.  
  3196. //LR: 1.7 not w/modified window titles!    GetWTitle( theWin, fileName );
  3197.         GetIndString( prompt, strPrompt, 1 );
  3198.         
  3199.         StandardPutFile( prompt, dWin->fsSpec.name, &reply );
  3200.         if( reply.sfGood )
  3201.         {
  3202.             dWin->destSpec = reply.sfFile;
  3203.             dWin->creationDate = 0;
  3204.             dWin->readOnlyFlag = false;
  3205.             SaveContents( theWin );
  3206.         }
  3207.     }
  3208. #endif
  3209.  
  3210.     _setWindowTitle( dWin );    // LR: 1.7 - set window title, append window to menu
  3211. }
  3212.  
  3213. /*** REVERT CONTENTS ***/
  3214. void RevertContents( WindowRef theWin )
  3215. {
  3216.     EditWindowPtr    dWin = (EditWindowPtr) GetWRefCon( theWin );
  3217.     long            newEOF;
  3218.  
  3219.     // Reset Work File
  3220.     dWin->workBytesWritten = 0L;
  3221.     SetEOF( dWin->workRefNum, 0L );
  3222.  
  3223.     // Clear linked list
  3224.     UnloadFile( dWin );
  3225.  
  3226.     // Reset EOF
  3227.     GetEOF( dWin->refNum, &newEOF );
  3228.  
  3229.     dWin->fileSize = newEOF;
  3230.  
  3231.     // Rebuilt linked list
  3232.     LoadFile( dWin );
  3233.  
  3234.     // Reset scroll offset, if necessary
  3235.     if( dWin->editOffset > dWin->fileSize - (kBytesPerLine * dWin->linesPerPage) )
  3236.         dWin->editOffset = 0;
  3237.  
  3238.     dWin->dirtyFlag = false;    //LR 1.72 -- no longer dirty :)
  3239.  
  3240.     //LR 1.72 -- release undo if associated with this window
  3241.     if( dWin == gUndo.theWin )
  3242.     {
  3243.         ReleaseEditScrap( dWin, &gUndo.undoScrap );
  3244.         gUndo.type = 0;
  3245.     }
  3246.     if( dWin == gRedo.theWin )
  3247.     {
  3248.         ReleaseEditScrap( dWin, &gRedo.undoScrap );
  3249.         gRedo.type = 0;
  3250.     }
  3251.  
  3252. //LR 180    DrawPage( dWin );
  3253.     UpdateOnscreen( theWin );
  3254. }
  3255.